Changeset View
Standalone View
sys/kern/kern_jail.c
Show First 20 Lines • Show All 569 Lines • ▼ Show 20 Lines | |||||||||||||||||||||
/* | /* | ||||||||||||||||||||
* Network address lists (pr_addrs) allocation for jails. The addresses | * Network address lists (pr_addrs) allocation for jails. The addresses | ||||||||||||||||||||
* are accessed locklessly by the network stack, thus need to be protected by | * are accessed locklessly by the network stack, thus need to be protected by | ||||||||||||||||||||
* the network epoch. | * the network epoch. | ||||||||||||||||||||
*/ | */ | ||||||||||||||||||||
struct prison_ip { | struct prison_ip { | ||||||||||||||||||||
struct epoch_context ctx; | struct epoch_context ctx; | ||||||||||||||||||||
uint32_t ips; | uint32_t ips; | ||||||||||||||||||||
#ifdef FUTURE_C | #ifdef FUTURE_C | ||||||||||||||||||||
/* | |||||||||||||||||||||
* XXX Variable-length automatic arrays in union may be | |||||||||||||||||||||
* supported in future C. | |||||||||||||||||||||
*/ | |||||||||||||||||||||
melifaro: Is this still needed? | |||||||||||||||||||||
Done Inline Actions
Variable length arrays are allowed in ISO C99. They are standard and more elegant. Zero-length arrays in struct / union is not allowed in ISO C but extensions of GCC (prior ISO C) and Clang. I'd prefer ISO ones as maybe the extension (of zero-length arrays) will be disabled and ISO ones is enforced in future. For now I'll remove it and leave a comment instead. zlei: > Is this still needed?
Variable length arrays are allowed in ISO C99. They are standard and… | |||||||||||||||||||||
union { | union { | ||||||||||||||||||||
char pr_ip[]; | |||||||||||||||||||||
struct in_addr pr_ip4[]; | struct in_addr pr_ip4[]; | ||||||||||||||||||||
struct in6_addr pr_ip6[]; | struct in6_addr pr_ip6[]; | ||||||||||||||||||||
}; | }; | ||||||||||||||||||||
#else /* No future C :( */ | #else /* No future C :( */ | ||||||||||||||||||||
#define PR_IP(pip, i) ((const char *)((pip) + 1) + pr_families[af].size * (i)) | char pr_ip[]; | ||||||||||||||||||||
#define PR_IPD(pip, i) ((char *)((pip) + 1) + pr_families[af].size * (i)) | |||||||||||||||||||||
#endif | #endif | ||||||||||||||||||||
}; | }; | ||||||||||||||||||||
Done Inline Actions
Maybe it's worth converting the macro to the function, so we get type checking & argument asserts for free? melifaro: Maybe it's worth converting the macro to the function, so we get type checking & argument… | |||||||||||||||||||||
Done Inline ActionsThat make sense. zlei: That make sense. | |||||||||||||||||||||
Done Inline Actions
Compiler complains (char *) to (const char*) converting. So I have to define two functions. static const char * pr_ip_get(const struct prison_ip *pip, const pr_family_t af, int idx) { MPASS(pip); MPASS(af < PR_FAMILY_MAX); MPASS(idx >= 0); return (pip->pr_ip + pr_families[af].size * idx); } static char * pr_ip_get_d(struct prison_ip *pip, const pr_family_t af, int idx) { MPASS(pip); MPASS(af < PR_FAMILY_MAX); MPASS(idx >= 0); return (pip->pr_ip + pr_families[af].size * idx); } #define PR_IP(pip, i) (pr_ip_get((pip), af, (i))) #define PR_IPD(pip, i) (pr_ip_get_d((pip), af, (i))) That seems a bit of overkill . zlei: > Maybe it's worth converting the macro to the function, so we get type checking & argument… | |||||||||||||||||||||
Done Inline ActionsWell, I'd still prefer to have them. If we had this before, the issue spotted in D37872 ( case 0: bcopy(PR_IP(pr, i), PR_IPD(new, ips), size); ) would be caught by the compiler. melifaro: Well, I'd still prefer to have them.
In the prod version they'll effectively be the same one… | |||||||||||||||||||||
static char * | |||||||||||||||||||||
PR_IP(struct prison_ip *pip, const pr_family_t af, int idx) | |||||||||||||||||||||
{ | |||||||||||||||||||||
MPASS(pip); | |||||||||||||||||||||
MPASS(af < PR_FAMILY_MAX); | |||||||||||||||||||||
MPASS(idx >= 0 && idx < pip->ips); | |||||||||||||||||||||
return (pip->pr_ip + pr_families[af].size * idx); | |||||||||||||||||||||
} | |||||||||||||||||||||
static struct prison_ip * | static struct prison_ip * | ||||||||||||||||||||
prison_ip_alloc(const pr_family_t af, uint32_t cnt, int flags) | prison_ip_alloc(const pr_family_t af, uint32_t cnt, int flags) | ||||||||||||||||||||
{ | { | ||||||||||||||||||||
struct prison_ip *pip; | struct prison_ip *pip; | ||||||||||||||||||||
pip = malloc(sizeof(struct prison_ip) + cnt * pr_families[af].size, | pip = malloc(sizeof(struct prison_ip) + cnt * pr_families[af].size, | ||||||||||||||||||||
M_PRISON, flags); | M_PRISON, flags); | ||||||||||||||||||||
if (pip != NULL) | if (pip != NULL) | ||||||||||||||||||||
pip->ips = cnt; | pip->ips = cnt; | ||||||||||||||||||||
return (pip); | return (pip); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
/* | /* | ||||||||||||||||||||
* Allocate and copyin user supplied address list, sorting and validating. | * Allocate and copyin user supplied address list, sorting and validating. | ||||||||||||||||||||
* kern_jail_set() helper. | * kern_jail_set() helper. | ||||||||||||||||||||
*/ | */ | ||||||||||||||||||||
static struct prison_ip * | static struct prison_ip * | ||||||||||||||||||||
prison_ip_copyin(const pr_family_t af, void *op, uint32_t cnt) | prison_ip_copyin(const pr_family_t af, void *op, uint32_t cnt) | ||||||||||||||||||||
{ | { | ||||||||||||||||||||
prison_addr_cmp_t *const cmp = pr_families[af].cmp; | prison_addr_cmp_t *const cmp = pr_families[af].cmp; | ||||||||||||||||||||
const size_t size = pr_families[af].size; | const size_t size = pr_families[af].size; | ||||||||||||||||||||
struct prison_ip *pip; | struct prison_ip *pip; | ||||||||||||||||||||
pip = prison_ip_alloc(af, cnt, M_WAITOK); | pip = prison_ip_alloc(af, cnt, M_WAITOK); | ||||||||||||||||||||
bcopy(op, pip + 1, cnt * size); | bcopy(op, pip->pr_ip, cnt * size); | ||||||||||||||||||||
Done Inline Actions‘pr_ip’ is an array. IIRC the typical pattern is either ‘arr’ or ‘&arr[0]’ melifaro: ‘pr_ip’ is an array. IIRC the typical pattern is either ‘arr’ or ‘&arr[0]’ | |||||||||||||||||||||
Done Inline ActionsGood catch! Well &arr point to the same address as arr or &arr[0], but it has different type. &arr + 1 != arr + 1 . zlei: Good catch!
This is a middle night work and `&arr` is indeed wrong.
Well `&arr` point to the… | |||||||||||||||||||||
/* | /* | ||||||||||||||||||||
* IP addresses are all sorted but ip[0] to preserve | * IP addresses are all sorted but ip[0] to preserve | ||||||||||||||||||||
* the primary IP address as given from userland. | * the primary IP address as given from userland. | ||||||||||||||||||||
* This special IP is used for unbound outgoing | * This special IP is used for unbound outgoing | ||||||||||||||||||||
* connections as well for "loopback" traffic in case | * connections as well for "loopback" traffic in case | ||||||||||||||||||||
* source address selection cannot find any more fitting | * source address selection cannot find any more fitting | ||||||||||||||||||||
* address to connect from. | * address to connect from. | ||||||||||||||||||||
*/ | */ | ||||||||||||||||||||
if (cnt > 1) | if (cnt > 1) | ||||||||||||||||||||
qsort((char *)(pip + 1) + size, cnt - 1, size, | qsort(pip->pr_ip + size, cnt - 1, size, pr_families[af].cmp); | ||||||||||||||||||||
Done Inline Actions
Nit: maybe that's more readable? melifaro: Nit: maybe that's more readable? | |||||||||||||||||||||
Done Inline ActionsYes I think so. zlei: Yes I think so. | |||||||||||||||||||||
Done Inline Actions
Create separate differential D37890 so it will be easy to review. zlei: > Nit: maybe that's more readable?
Create separate differential D37890 so it will be easy to… | |||||||||||||||||||||
pr_families[af].cmp); | |||||||||||||||||||||
/* | /* | ||||||||||||||||||||
* Check for duplicate addresses and do some simple | * Check for duplicate addresses and do some simple | ||||||||||||||||||||
* zero and broadcast checks. If users give other bogus | * zero and broadcast checks. If users give other bogus | ||||||||||||||||||||
* addresses it is their problem. | * addresses it is their problem. | ||||||||||||||||||||
*/ | */ | ||||||||||||||||||||
for (int i = 0; i < cnt; i++) { | for (int i = 0; i < cnt; i++) { | ||||||||||||||||||||
if (!pr_families[af].valid(PR_IP(pip, i))) { | if (!pr_families[af].valid(PR_IP(pip, af, i))) { | ||||||||||||||||||||
free(pip, M_PRISON); | free(pip, M_PRISON); | ||||||||||||||||||||
return (NULL); | return (NULL); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
if (i + 1 < cnt && | if (i + 1 < cnt && | ||||||||||||||||||||
(cmp(PR_IP(pip, 0), PR_IP(pip, i + 1)) == 0 || | (cmp(PR_IP(pip, af, 0), PR_IP(pip, af, i + 1)) == 0 || | ||||||||||||||||||||
cmp(PR_IP(pip, i), PR_IP(pip, i + 1)) == 0)) { | cmp(PR_IP(pip, af, i), PR_IP(pip, af, i + 1)) == 0)) { | ||||||||||||||||||||
free(pip, M_PRISON); | free(pip, M_PRISON); | ||||||||||||||||||||
return (NULL); | return (NULL); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
} | } | ||||||||||||||||||||
return (pip); | return (pip); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
/* | /* | ||||||||||||||||||||
* Allocate and dup parent prison address list. | * Allocate and dup parent prison address list. | ||||||||||||||||||||
* kern_jail_set() helper. | * kern_jail_set() helper. | ||||||||||||||||||||
*/ | */ | ||||||||||||||||||||
static void | static void | ||||||||||||||||||||
prison_ip_dup(struct prison *ppr, struct prison *pr, const pr_family_t af) | prison_ip_dup(struct prison *ppr, struct prison *pr, const pr_family_t af) | ||||||||||||||||||||
{ | { | ||||||||||||||||||||
if (ppr->pr_addrs[af] != NULL) { | if (ppr->pr_addrs[af] != NULL) { | ||||||||||||||||||||
pr->pr_addrs[af] = prison_ip_alloc(af, | pr->pr_addrs[af] = prison_ip_alloc(af, | ||||||||||||||||||||
ppr->pr_addrs[af]->ips, M_WAITOK); | ppr->pr_addrs[af]->ips, M_WAITOK); | ||||||||||||||||||||
bcopy(ppr->pr_addrs[af] + 1, pr->pr_addrs[af] + 1, | bcopy(ppr->pr_addrs[af]->pr_ip, pr->pr_addrs[af]->pr_ip, | ||||||||||||||||||||
pr->pr_addrs[af]->ips * pr_families[af].size); | pr->pr_addrs[af]->ips * pr_families[af].size); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
} | } | ||||||||||||||||||||
/* | /* | ||||||||||||||||||||
* Make sure the new set of IP addresses is a subset of the parent's list. | * Make sure the new set of IP addresses is a subset of the parent's list. | ||||||||||||||||||||
* Don't worry about the parent being unlocked, as any setting is done with | * Don't worry about the parent being unlocked, as any setting is done with | ||||||||||||||||||||
* allprison_lock held. | * allprison_lock held. | ||||||||||||||||||||
* kern_jail_set() helper. | * kern_jail_set() helper. | ||||||||||||||||||||
*/ | */ | ||||||||||||||||||||
static bool | static bool | ||||||||||||||||||||
prison_ip_parent_match(const struct prison_ip *ppip, | prison_ip_parent_match(struct prison_ip *ppip, struct prison_ip *pip, | ||||||||||||||||||||
const struct prison_ip *pip, const pr_family_t af) | const pr_family_t af) | ||||||||||||||||||||
{ | { | ||||||||||||||||||||
prison_addr_cmp_t *const cmp = pr_families[af].cmp; | prison_addr_cmp_t *const cmp = pr_families[af].cmp; | ||||||||||||||||||||
int i, j; | int i, j; | ||||||||||||||||||||
if (ppip == NULL) | if (ppip == NULL) | ||||||||||||||||||||
return (false); | return (false); | ||||||||||||||||||||
for (i = 0; i < ppip->ips; i++) | for (i = 0; i < ppip->ips; i++) | ||||||||||||||||||||
if (cmp(PR_IP(pip, 0), PR_IP(ppip, i)) == 0) | if (cmp(PR_IP(pip, af, 0), PR_IP(ppip, af, i)) == 0) | ||||||||||||||||||||
break; | break; | ||||||||||||||||||||
if (i == ppip->ips) | if (i == ppip->ips) | ||||||||||||||||||||
/* Main address not present in parent. */ | /* Main address not present in parent. */ | ||||||||||||||||||||
return (false); | return (false); | ||||||||||||||||||||
if (pip->ips > 1) { | if (pip->ips > 1) { | ||||||||||||||||||||
for (i = j = 1; i < pip->ips; i++) { | for (i = j = 1; i < pip->ips; i++) { | ||||||||||||||||||||
if (cmp(PR_IP(pip, i), PR_IP(ppip, 0)) == 0) | if (cmp(PR_IP(pip, af, i), PR_IP(ppip, af, 0)) == 0) | ||||||||||||||||||||
/* Equals to parent primary address. */ | /* Equals to parent primary address. */ | ||||||||||||||||||||
continue; | continue; | ||||||||||||||||||||
for (; j < ppip->ips; j++) | for (; j < ppip->ips; j++) | ||||||||||||||||||||
if (cmp(PR_IP(pip, i), PR_IP(ppip, j)) == 0) | if (cmp(PR_IP(pip, af, i), | ||||||||||||||||||||
PR_IP(ppip, af, j)) == 0) | |||||||||||||||||||||
break; | break; | ||||||||||||||||||||
if (j == ppip->ips) | if (j == ppip->ips) | ||||||||||||||||||||
break; | break; | ||||||||||||||||||||
} | } | ||||||||||||||||||||
if (j == ppip->ips) | if (j == ppip->ips) | ||||||||||||||||||||
/* Address not present in parent. */ | /* Address not present in parent. */ | ||||||||||||||||||||
return (false); | return (false); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
return (true); | return (true); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
/* | /* | ||||||||||||||||||||
* Check for conflicting IP addresses. We permit them if there is no more | * Check for conflicting IP addresses. We permit them if there is no more | ||||||||||||||||||||
* than one IP on each jail. If there is a duplicate on a jail with more | * than one IP on each jail. If there is a duplicate on a jail with more | ||||||||||||||||||||
* than one IP stop checking and return error. | * than one IP stop checking and return error. | ||||||||||||||||||||
* kern_jail_set() helper. | * kern_jail_set() helper. | ||||||||||||||||||||
*/ | */ | ||||||||||||||||||||
static bool | static bool | ||||||||||||||||||||
prison_ip_conflict_check(const struct prison *ppr, const struct prison *pr, | prison_ip_conflict_check(const struct prison *ppr, const struct prison *pr, | ||||||||||||||||||||
const struct prison_ip *pip, pr_family_t af) | struct prison_ip *pip, pr_family_t af) | ||||||||||||||||||||
{ | { | ||||||||||||||||||||
const struct prison *tppr, *tpr; | const struct prison *tppr, *tpr; | ||||||||||||||||||||
int descend; | int descend; | ||||||||||||||||||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||||||||||||||||||
for (tppr = ppr; tppr != &prison0; tppr = tppr->pr_parent) | for (tppr = ppr; tppr != &prison0; tppr = tppr->pr_parent) | ||||||||||||||||||||
if (tppr->pr_flags & PR_VNET) | if (tppr->pr_flags & PR_VNET) | ||||||||||||||||||||
break; | break; | ||||||||||||||||||||
Show All 11 Lines | #endif | ||||||||||||||||||||
} | } | ||||||||||||||||||||
if (!(tpr->pr_flags & pr_families[af].ip_flag)) | if (!(tpr->pr_flags & pr_families[af].ip_flag)) | ||||||||||||||||||||
continue; | continue; | ||||||||||||||||||||
descend = 0; | descend = 0; | ||||||||||||||||||||
if (tpr->pr_addrs[af] == NULL || | if (tpr->pr_addrs[af] == NULL || | ||||||||||||||||||||
(pip->ips == 1 && tpr->pr_addrs[af]->ips == 1)) | (pip->ips == 1 && tpr->pr_addrs[af]->ips == 1)) | ||||||||||||||||||||
continue; | continue; | ||||||||||||||||||||
for (int i = 0; i < pip->ips; i++) | for (int i = 0; i < pip->ips; i++) | ||||||||||||||||||||
if (prison_ip_check(tpr, af, PR_IP(pip, i)) == 0) | if (prison_ip_check(tpr, af, PR_IP(pip, af, i)) == 0) | ||||||||||||||||||||
return (false); | return (false); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
return (true); | return (true); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
_Static_assert(offsetof(struct prison_ip, ctx) == 0, | _Static_assert(offsetof(struct prison_ip, ctx) == 0, | ||||||||||||||||||||
"prison must start with epoch context"); | "prison must start with epoch context"); | ||||||||||||||||||||
Show All 30 Lines | |||||||||||||||||||||
* Restrict a prison's IP address list with its parent's, possibly replacing | * Restrict a prison's IP address list with its parent's, possibly replacing | ||||||||||||||||||||
* it. Return true if succeed, otherwise should redo. | * it. Return true if succeed, otherwise should redo. | ||||||||||||||||||||
* kern_jail_set() helper. | * kern_jail_set() helper. | ||||||||||||||||||||
*/ | */ | ||||||||||||||||||||
static bool | static bool | ||||||||||||||||||||
prison_ip_restrict(struct prison *pr, const pr_family_t af, | prison_ip_restrict(struct prison *pr, const pr_family_t af, | ||||||||||||||||||||
struct prison_ip **newp) | struct prison_ip **newp) | ||||||||||||||||||||
{ | { | ||||||||||||||||||||
const struct prison_ip *ppip = pr->pr_parent->pr_addrs[af]; | struct prison_ip *ppip = pr->pr_parent->pr_addrs[af]; | ||||||||||||||||||||
const struct prison_ip *pip = pr->pr_addrs[af]; | struct prison_ip *pip = pr->pr_addrs[af]; | ||||||||||||||||||||
int (*const cmp)(const void *, const void *) = pr_families[af].cmp; | int (*const cmp)(const void *, const void *) = pr_families[af].cmp; | ||||||||||||||||||||
const size_t size = pr_families[af].size; | const size_t size = pr_families[af].size; | ||||||||||||||||||||
struct prison_ip *new = newp != NULL ? *newp : NULL; | struct prison_ip *new = newp != NULL ? *newp : NULL; | ||||||||||||||||||||
uint32_t ips; | uint32_t ips; | ||||||||||||||||||||
mtx_assert(&pr->pr_mtx, MA_OWNED); | mtx_assert(&pr->pr_mtx, MA_OWNED); | ||||||||||||||||||||
/* | /* | ||||||||||||||||||||
Show All 10 Lines | prison_ip_restrict(struct prison *pr, const pr_family_t af, | ||||||||||||||||||||
} | } | ||||||||||||||||||||
if (!(pr->pr_flags & pr_families[af].ip_flag)) { | if (!(pr->pr_flags & pr_families[af].ip_flag)) { | ||||||||||||||||||||
if (new == NULL) { | if (new == NULL) { | ||||||||||||||||||||
new = prison_ip_alloc(af, ppip->ips, M_NOWAIT); | new = prison_ip_alloc(af, ppip->ips, M_NOWAIT); | ||||||||||||||||||||
if (new == NULL) | if (new == NULL) | ||||||||||||||||||||
return (false); /* Redo */ | return (false); /* Redo */ | ||||||||||||||||||||
} | } | ||||||||||||||||||||
/* This has no user settings, so just copy the parent's list. */ | /* This has no user settings, so just copy the parent's list. */ | ||||||||||||||||||||
MPASS(new->ips == ppip->ips); | MPASS(new->ips == ppip->ips); | ||||||||||||||||||||
Done Inline Actions&ppip->pr_ip -> ppip->pr_ip zlei: `&ppip->pr_ip` -> `ppip->pr_ip` | |||||||||||||||||||||
bcopy(ppip + 1, new + 1, ppip->ips * size); | bcopy(ppip->pr_ip, new->pr_ip, ppip->ips * size); | ||||||||||||||||||||
prison_ip_set(pr, af, new); | prison_ip_set(pr, af, new); | ||||||||||||||||||||
if (newp != NULL) | if (newp != NULL) | ||||||||||||||||||||
*newp = NULL; /* Used */ | *newp = NULL; /* Used */ | ||||||||||||||||||||
} else if (pip != NULL) { | } else if (pip != NULL) { | ||||||||||||||||||||
/* Remove addresses that aren't in the parent. */ | /* Remove addresses that aren't in the parent. */ | ||||||||||||||||||||
int i; | int i; | ||||||||||||||||||||
i = 0; /* index in pip */ | i = 0; /* index in pip */ | ||||||||||||||||||||
ips = 0; /* index in new */ | ips = 0; /* index in new */ | ||||||||||||||||||||
if (new == NULL) { | if (new == NULL) { | ||||||||||||||||||||
new = prison_ip_alloc(af, pip->ips, M_NOWAIT); | new = prison_ip_alloc(af, pip->ips, M_NOWAIT); | ||||||||||||||||||||
if (new == NULL) | if (new == NULL) | ||||||||||||||||||||
return (false); /* Redo */ | return (false); /* Redo */ | ||||||||||||||||||||
} | } | ||||||||||||||||||||
for (int pi = 0; pi < ppip->ips; pi++) | for (int pi = 0; pi < ppip->ips; pi++) | ||||||||||||||||||||
if (cmp(PR_IP(pip, 0), PR_IP(ppip, pi)) == 0) { | if (cmp(PR_IP(pip, af, 0), PR_IP(ppip, af, pi)) == 0) { | ||||||||||||||||||||
/* Found our primary address in parent. */ | /* Found our primary address in parent. */ | ||||||||||||||||||||
bcopy(PR_IP(pip, i), PR_IPD(new, ips), size); | bcopy(PR_IP(pip, af, i), PR_IP(new, af, ips), | ||||||||||||||||||||
size); | |||||||||||||||||||||
i++; | i++; | ||||||||||||||||||||
ips++; | ips++; | ||||||||||||||||||||
break; | break; | ||||||||||||||||||||
} | } | ||||||||||||||||||||
for (int pi = 1; i < pip->ips; ) { | for (int pi = 1; i < pip->ips; ) { | ||||||||||||||||||||
/* Check against primary, which is unsorted. */ | /* Check against primary, which is unsorted. */ | ||||||||||||||||||||
if (cmp(PR_IP(pip, i), PR_IP(ppip, 0)) == 0) { | if (cmp(PR_IP(pip, af, i), PR_IP(ppip, af, 0)) == 0) { | ||||||||||||||||||||
/* Matches parent's primary address. */ | /* Matches parent's primary address. */ | ||||||||||||||||||||
bcopy(PR_IP(pip, i), PR_IPD(new, ips), size); | bcopy(PR_IP(pip, af, i), PR_IP(new, af, ips), | ||||||||||||||||||||
size); | |||||||||||||||||||||
i++; | i++; | ||||||||||||||||||||
ips++; | ips++; | ||||||||||||||||||||
continue; | continue; | ||||||||||||||||||||
} | } | ||||||||||||||||||||
/* The rest are sorted. */ | /* The rest are sorted. */ | ||||||||||||||||||||
switch (pi >= ppip->ips ? -1 : | switch (pi >= ppip->ips ? -1 : | ||||||||||||||||||||
cmp(PR_IP(pip, i), PR_IP(ppip, pi))) { | cmp(PR_IP(pip, af, i), PR_IP(ppip, af, pi))) { | ||||||||||||||||||||
case -1: | case -1: | ||||||||||||||||||||
i++; | i++; | ||||||||||||||||||||
break; | break; | ||||||||||||||||||||
case 0: | case 0: | ||||||||||||||||||||
bcopy(PR_IP(pip, i), PR_IPD(new, ips), size); | bcopy(PR_IP(pip, af, i), PR_IP(new, af, ips), | ||||||||||||||||||||
size); | |||||||||||||||||||||
i++; | i++; | ||||||||||||||||||||
pi++; | pi++; | ||||||||||||||||||||
ips++; | ips++; | ||||||||||||||||||||
break; | break; | ||||||||||||||||||||
case 1: | case 1: | ||||||||||||||||||||
pi++; | pi++; | ||||||||||||||||||||
break; | break; | ||||||||||||||||||||
} | } | ||||||||||||||||||||
Show All 18 Lines | |||||||||||||||||||||
/* | /* | ||||||||||||||||||||
* Fast-path check if an address belongs to a prison. | * Fast-path check if an address belongs to a prison. | ||||||||||||||||||||
*/ | */ | ||||||||||||||||||||
int | int | ||||||||||||||||||||
prison_ip_check(const struct prison *pr, const pr_family_t af, | prison_ip_check(const struct prison *pr, const pr_family_t af, | ||||||||||||||||||||
const void *addr) | const void *addr) | ||||||||||||||||||||
{ | { | ||||||||||||||||||||
int (*const cmp)(const void *, const void *) = pr_families[af].cmp; | int (*const cmp)(const void *, const void *) = pr_families[af].cmp; | ||||||||||||||||||||
const struct prison_ip *pip; | struct prison_ip *pip; | ||||||||||||||||||||
int i, a, z, d; | int i, a, z, d; | ||||||||||||||||||||
MPASS(mtx_owned(&pr->pr_mtx) || | MPASS(mtx_owned(&pr->pr_mtx) || | ||||||||||||||||||||
in_epoch(net_epoch_preempt) || | in_epoch(net_epoch_preempt) || | ||||||||||||||||||||
sx_xlocked(&allprison_lock)); | sx_xlocked(&allprison_lock)); | ||||||||||||||||||||
pip = atomic_load_ptr(&pr->pr_addrs[af]); | pip = atomic_load_ptr(&pr->pr_addrs[af]); | ||||||||||||||||||||
if (__predict_false(pip == NULL)) | if (__predict_false(pip == NULL)) | ||||||||||||||||||||
return (EAFNOSUPPORT); | return (EAFNOSUPPORT); | ||||||||||||||||||||
/* Check the primary IP. */ | /* Check the primary IP. */ | ||||||||||||||||||||
if (cmp(PR_IP(pip, 0), addr) == 0) | if (cmp(PR_IP(pip, af, 0), addr) == 0) | ||||||||||||||||||||
return (0); | return (0); | ||||||||||||||||||||
/* | /* | ||||||||||||||||||||
* All the other IPs are sorted so we can do a binary search. | * All the other IPs are sorted so we can do a binary search. | ||||||||||||||||||||
*/ | */ | ||||||||||||||||||||
a = 0; | a = 0; | ||||||||||||||||||||
z = pip->ips - 2; | z = pip->ips - 2; | ||||||||||||||||||||
while (a <= z) { | while (a <= z) { | ||||||||||||||||||||
i = (a + z) / 2; | i = (a + z) / 2; | ||||||||||||||||||||
d = cmp(PR_IP(pip, i + 1), addr); | d = cmp(PR_IP(pip, af, i + 1), addr); | ||||||||||||||||||||
if (d > 0) | if (d > 0) | ||||||||||||||||||||
z = i - 1; | z = i - 1; | ||||||||||||||||||||
else if (d < 0) | else if (d < 0) | ||||||||||||||||||||
a = i + 1; | a = i + 1; | ||||||||||||||||||||
else | else | ||||||||||||||||||||
return (0); | return (0); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
return (EADDRNOTAVAIL); | return (EADDRNOTAVAIL); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
/* | /* | ||||||||||||||||||||
* Grab primary IP. Historically required mutex, but nothing prevents | * Grab primary IP. Historically required mutex, but nothing prevents | ||||||||||||||||||||
* us to support epoch-protected access. Is it used in fast path? | * us to support epoch-protected access. Is it used in fast path? | ||||||||||||||||||||
* in{6}_jail.c helper | * in{6}_jail.c helper | ||||||||||||||||||||
*/ | */ | ||||||||||||||||||||
const void * | const void * | ||||||||||||||||||||
prison_ip_get0(const struct prison *pr, const pr_family_t af) | prison_ip_get0(const struct prison *pr, const pr_family_t af) | ||||||||||||||||||||
{ | { | ||||||||||||||||||||
const struct prison_ip *pip = pr->pr_addrs[af]; | const struct prison_ip *pip = pr->pr_addrs[af]; | ||||||||||||||||||||
mtx_assert(&pr->pr_mtx, MA_OWNED); | mtx_assert(&pr->pr_mtx, MA_OWNED); | ||||||||||||||||||||
MPASS(pip); | MPASS(pip); | ||||||||||||||||||||
return (pip + 1); | return (pip->pr_ip); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
u_int | u_int | ||||||||||||||||||||
prison_ip_cnt(const struct prison *pr, const pr_family_t af) | prison_ip_cnt(const struct prison *pr, const pr_family_t af) | ||||||||||||||||||||
{ | { | ||||||||||||||||||||
return (pr->pr_addrs[af]->ips); | return (pr->pr_addrs[af]->ips); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
▲ Show 20 Lines • Show All 1,418 Lines • ▼ Show 20 Lines | found_prison: | ||||||||||||||||||||
error = vfs_setopt(opts, "cpuset.id", &pr->pr_cpuset->cs_id, | error = vfs_setopt(opts, "cpuset.id", &pr->pr_cpuset->cs_id, | ||||||||||||||||||||
sizeof(pr->pr_cpuset->cs_id)); | sizeof(pr->pr_cpuset->cs_id)); | ||||||||||||||||||||
if (error != 0 && error != ENOENT) | if (error != 0 && error != ENOENT) | ||||||||||||||||||||
goto done; | goto done; | ||||||||||||||||||||
error = vfs_setopts(opts, "path", prison_path(mypr, pr)); | error = vfs_setopts(opts, "path", prison_path(mypr, pr)); | ||||||||||||||||||||
if (error != 0 && error != ENOENT) | if (error != 0 && error != ENOENT) | ||||||||||||||||||||
goto done; | goto done; | ||||||||||||||||||||
#ifdef INET | #ifdef INET | ||||||||||||||||||||
error = vfs_setopt_part(opts, "ip4.addr", pr->pr_addrs[PR_INET] + 1, | error = vfs_setopt_part(opts, "ip4.addr", pr->pr_addrs[PR_INET]->pr_ip, | ||||||||||||||||||||
Done Inline ActionsIf pr->pr_addrs[PR_INET] is NULL (as the line below suggest) won't it crash? melifaro: If `pr->pr_addrs[PR_INET]` is NULL (as the line below suggest) won't it crash?
Same for IPv6… | |||||||||||||||||||||
Done Inline ActionsNo, it won't crash. Checked the implementation of vfs_setopt_part(struct vfsoptlist *opts, const char *name, void *value, int len), it internally calls bcopy(value, opt->value, len). As per BCOPY(3),
If pr->pr_addrs[PR_INET(6)] is null then len will be zero, and bcopy() will behave as a nop. zlei: No, it won't crash.
Checked the implementation of `vfs_setopt_part(struct vfsoptlist *opts… | |||||||||||||||||||||
Done Inline ActionsMm. I meant that in order to call vfs_setopt_part(), the code has to resolve its arguments first. melifaro: Mm. I meant that in order to call `vfs_setopt_part()`, the code has to resolve its arguments… | |||||||||||||||||||||
Done Inline ActionsOoh, my fault. For short no side effect. Although pr->pr_addrs[PR_INET] might be NULL but we are not dereferencing NULL pointer. It looks tricky but pr_ip4 is an (zero sized) array. I'll demonstrate that online https://godbolt.org/z/f4hq63rdj zlei: Ooh, my fault.
For short no side effect.
Although `pr->pr_addrs[PR_INET]` might be `NULL` but… | |||||||||||||||||||||
Done Inline ActionsYep. My bad. For some reason, the idea that pr_ip4 has a separate pointer was stuck in my head. melifaro: Yep. My bad. For some reason, the idea that `pr_ip4` has a separate pointer was stuck in my… | |||||||||||||||||||||
pr->pr_addrs[PR_INET] ? pr->pr_addrs[PR_INET]->ips * | pr->pr_addrs[PR_INET] ? pr->pr_addrs[PR_INET]->ips * | ||||||||||||||||||||
pr_families[PR_INET].size : 0 ); | pr_families[PR_INET].size : 0 ); | ||||||||||||||||||||
if (error != 0 && error != ENOENT) | if (error != 0 && error != ENOENT) | ||||||||||||||||||||
goto done; | goto done; | ||||||||||||||||||||
#endif | #endif | ||||||||||||||||||||
#ifdef INET6 | #ifdef INET6 | ||||||||||||||||||||
error = vfs_setopt_part(opts, "ip6.addr", pr->pr_addrs[PR_INET6] + 1, | error = vfs_setopt_part(opts, "ip6.addr", pr->pr_addrs[PR_INET6]->pr_ip, | ||||||||||||||||||||
pr->pr_addrs[PR_INET6] ? pr->pr_addrs[PR_INET6]->ips * | pr->pr_addrs[PR_INET6] ? pr->pr_addrs[PR_INET6]->ips * | ||||||||||||||||||||
pr_families[PR_INET6].size : 0 ); | pr_families[PR_INET6].size : 0 ); | ||||||||||||||||||||
if (error != 0 && error != ENOENT) | if (error != 0 && error != ENOENT) | ||||||||||||||||||||
goto done; | goto done; | ||||||||||||||||||||
#endif | #endif | ||||||||||||||||||||
error = vfs_setopt(opts, "securelevel", &pr->pr_securelevel, | error = vfs_setopt(opts, "securelevel", &pr->pr_securelevel, | ||||||||||||||||||||
sizeof(pr->pr_securelevel)); | sizeof(pr->pr_securelevel)); | ||||||||||||||||||||
if (error != 0 && error != ENOENT) | if (error != 0 && error != ENOENT) | ||||||||||||||||||||
▲ Show 20 Lines • Show All 1,798 Lines • ▼ Show 20 Lines | again: | ||||||||||||||||||||
if (pr->pr_addrs[af] != NULL) { | if (pr->pr_addrs[af] != NULL) { | ||||||||||||||||||||
if (*len < pr->pr_addrs[af]->ips) { | if (*len < pr->pr_addrs[af]->ips) { | ||||||||||||||||||||
*len = pr->pr_addrs[af]->ips; | *len = pr->pr_addrs[af]->ips; | ||||||||||||||||||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||||||||||||||||||
*out = realloc(*out, *len * size, M_TEMP, M_WAITOK); | *out = realloc(*out, *len * size, M_TEMP, M_WAITOK); | ||||||||||||||||||||
mtx_lock(&pr->pr_mtx); | mtx_lock(&pr->pr_mtx); | ||||||||||||||||||||
goto again; | goto again; | ||||||||||||||||||||
} | } | ||||||||||||||||||||
bcopy(pr->pr_addrs[af] + 1, *out, pr->pr_addrs[af]->ips * size); | bcopy(pr->pr_addrs[af]->pr_ip, *out, pr->pr_addrs[af]->ips * size); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
} | } | ||||||||||||||||||||
#endif | #endif | ||||||||||||||||||||
static int | static int | ||||||||||||||||||||
sysctl_jail_list(SYSCTL_HANDLER_ARGS) | sysctl_jail_list(SYSCTL_HANDLER_ARGS) | ||||||||||||||||||||
{ | { | ||||||||||||||||||||
struct xprison *xp; | struct xprison *xp; | ||||||||||||||||||||
▲ Show 20 Lines • Show All 658 Lines • ▼ Show 20 Lines | |||||||||||||||||||||
static void | static void | ||||||||||||||||||||
db_show_prison(struct prison *pr) | db_show_prison(struct prison *pr) | ||||||||||||||||||||
{ | { | ||||||||||||||||||||
struct bool_flags *bf; | struct bool_flags *bf; | ||||||||||||||||||||
struct jailsys_flags *jsf; | struct jailsys_flags *jsf; | ||||||||||||||||||||
#if defined(INET) || defined(INET6) | #if defined(INET) || defined(INET6) | ||||||||||||||||||||
int ii; | int ii; | ||||||||||||||||||||
struct prison_ip *pip; | |||||||||||||||||||||
#endif | #endif | ||||||||||||||||||||
unsigned f; | unsigned f; | ||||||||||||||||||||
#ifdef INET | #ifdef INET | ||||||||||||||||||||
char ip4buf[INET_ADDRSTRLEN]; | char ip4buf[INET_ADDRSTRLEN]; | ||||||||||||||||||||
#endif | #endif | ||||||||||||||||||||
#ifdef INET6 | #ifdef INET6 | ||||||||||||||||||||
char ip6buf[INET6_ADDRSTRLEN]; | char ip6buf[INET6_ADDRSTRLEN]; | ||||||||||||||||||||
#endif | #endif | ||||||||||||||||||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (pr->pr_allow & bf->flag) | ||||||||||||||||||||
db_printf(" %s", bf->name); | db_printf(" %s", bf->name); | ||||||||||||||||||||
db_printf("\n"); | db_printf("\n"); | ||||||||||||||||||||
db_printf(" enforce_statfs = %d\n", pr->pr_enforce_statfs); | db_printf(" enforce_statfs = %d\n", pr->pr_enforce_statfs); | ||||||||||||||||||||
db_printf(" host.hostname = %s\n", pr->pr_hostname); | db_printf(" host.hostname = %s\n", pr->pr_hostname); | ||||||||||||||||||||
db_printf(" host.domainname = %s\n", pr->pr_domainname); | db_printf(" host.domainname = %s\n", pr->pr_domainname); | ||||||||||||||||||||
db_printf(" host.hostuuid = %s\n", pr->pr_hostuuid); | db_printf(" host.hostuuid = %s\n", pr->pr_hostuuid); | ||||||||||||||||||||
db_printf(" host.hostid = %lu\n", pr->pr_hostid); | db_printf(" host.hostid = %lu\n", pr->pr_hostid); | ||||||||||||||||||||
#ifdef INET | #ifdef INET | ||||||||||||||||||||
if (pr->pr_addrs[PR_INET] != NULL) { | if ((pip = pr->pr_addrs[PR_INET]) != NULL) { | ||||||||||||||||||||
pr_family_t af = PR_INET; | db_printf(" ip4s = %d\n", pip->ips); | ||||||||||||||||||||
for (ii = 0; ii < pip->ips; ii++) | |||||||||||||||||||||
db_printf(" ip4s = %d\n", pr->pr_addrs[af]->ips); | |||||||||||||||||||||
for (ii = 0; ii < pr->pr_addrs[af]->ips; ii++) | |||||||||||||||||||||
db_printf(" %s %s\n", | db_printf(" %s %s\n", | ||||||||||||||||||||
ii == 0 ? "ip4.addr =" : " ", | ii == 0 ? "ip4.addr =" : " ", | ||||||||||||||||||||
inet_ntoa_r( | inet_ntoa_r( | ||||||||||||||||||||
*(const struct in_addr *)PR_IP(pr->pr_addrs[af], ii), | *(const struct in_addr *)PR_IP(pip, PR_INET, ii), | ||||||||||||||||||||
ip4buf)); | ip4buf)); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
#endif | #endif | ||||||||||||||||||||
#ifdef INET6 | #ifdef INET6 | ||||||||||||||||||||
if (pr->pr_addrs[PR_INET6] != NULL) { | if ((pip = pr->pr_addrs[PR_INET6]) != NULL) { | ||||||||||||||||||||
pr_family_t af = PR_INET6; | db_printf(" ip6s = %d\n", pip->ips); | ||||||||||||||||||||
for (ii = 0; ii < pip->ips; ii++) | |||||||||||||||||||||
db_printf(" ip6s = %d\n", pr->pr_addrs[af]->ips); | |||||||||||||||||||||
for (ii = 0; ii < pr->pr_addrs[af]->ips; ii++) | |||||||||||||||||||||
db_printf(" %s %s\n", | db_printf(" %s %s\n", | ||||||||||||||||||||
ii == 0 ? "ip6.addr =" : " ", | ii == 0 ? "ip6.addr =" : " ", | ||||||||||||||||||||
ip6_sprintf(ip6buf, | ip6_sprintf(ip6buf, | ||||||||||||||||||||
(const struct in6_addr *)PR_IP(pr->pr_addrs[af], ii))); | (const struct in6_addr *)PR_IP(pip, PR_INET6, ii))); | ||||||||||||||||||||
} | } | ||||||||||||||||||||
#endif | #endif | ||||||||||||||||||||
} | } | ||||||||||||||||||||
DB_SHOW_COMMAND(prison, db_show_prison_command) | DB_SHOW_COMMAND(prison, db_show_prison_command) | ||||||||||||||||||||
{ | { | ||||||||||||||||||||
struct prison *pr; | struct prison *pr; | ||||||||||||||||||||
Show All 36 Lines |
Is this still needed?