Re: Add IP address ioctl (SIOCAIFADDR) from jail is called with host credentials

From: Alexander Chernikov <melifaro_at_FreeBSD.org>
Date: Thu, 29 Jun 2023 07:05:43 UTC

> On 28 Jun 2023, at 22:59, Alexander Chernikov <melifaro@freebsd.org> wrote:
> 
> 
> 
> On Wed, 28 Jun 2023, at 6:30 AM, Shivank Garg wrote:
>> Hi Alexander,
>> 
>> Thanks for replying.
>> I think it would mean struct prison info is lost, when it reaches ioctl code, Is there some way we can get jail id?
> Yes, you should add the hook to the netlink handler.
>> 
>> Another question I have: prison_check_ip4 still relies on checking struct prison for flags and ip addr. 
>> https://github.com/freebsd/freebsd-src/blob/6927176113ee775983952edb3c201fed6be318d3/sys/netinet/in_jail.c#L319
>> How do we handle these cases?
> I’ll take a look on the weekend. It may indeed be a problem with nested jails.
I looked at the code and after some experiments decided to go with the simplest approach: https://reviews.freebsd.org/D40793
Netlink now passes proper ucred to the ioctl handler, so your code should be able to work out-of-the-box after this lands.

>> 
>>  It used to work for VNET jails inet calls sometime back when I wrote mac_ipacl: https://reviews.freebsd.org/D20967
>> - MAC policy to limit jail privilege to set its IP address. We were planning to merge this code in 14.0. Is there something we can
>> do regarding it?
> Yep, sure! I’ll try to further decouple ioctl handler and the actual address modification code so the ioctl hook wont’t get called in the netlink handler.
>> Thanks,
>> Shivank
>> 
>> On Wed, 28 Jun 2023 at 04:05, Alexander Chernikov <melifaro@freebsd.org <mailto:melifaro@freebsd.org>> wrote:
>> 
>> 
>> 
>> On Fri, 23 Jun 2023, at 10:27 AM, Alexander Chernikov wrote:
>>> 
>>> 
>>> On Fri, 23 Jun 2023, at 7:53 AM, Shivank Garg wrote:
>>>> Hi,
>>>> 
>>>> I want to check credentials of the thread setting the IP address with SIOCAIFADDR ioctl.
>>>> If the thread is jailed (jailed(td_ucred) == 1), I'm applying some checks on ip address.
>>>> 
>>>> My expectation was that (cred->cr_prison != &prison0) for an ifconfig call made by the jail.
>>> If you’re using -head, it’s a bit more complicated. ifconfig(8) uses rtnetlink(4) interfaces to communicate with the kernel. Privilege check is done in Netlink:  https://github.com/freebsd/freebsd-src/blob/764464af49688e74fd6d803df0404ca4726dd460/sys/netlink/route/iface.c#L1472 . After that, (as of now) netlink calls ioctl code from its own kernel thread, which may be the reason of the behavior you’re observing.
>> Apparently the previous message was not delivered everywhere.
>>>> However, it is showing me some weird behavior. Here are the logs for a tweaked kernel:
>>>> 
>>>> @@ -339,7 +343,7 @@ in_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp,
>>>>                 return (EADDRNOTAVAIL);
>>>>         struct ucred *cred = (td != NULL) ? td->td_ucred : NULL;
>>>> -
>>>> +       printf("in_control jailed? %d jid %d prison_owns_vnet? %d\n",jailed(cred),cred->cr_prison->pr_id,prison_owns_vnet(cred));
>>>> 
>>>> # jexec 1 ifconfig epair0b inet 169.254.123.101/24 <http://169.254.123.101/24> up
>>>> 
>>>> Dmesg logs:
>>>> [256] in_control jailed? 0 jid 0 prison_owns_vnet? 1
>>>> 
>>>> Cred value indicates host and jail is 0 but the PR_VNET flag is set.
>>>> 
>>>> Is this behavior expected? or something going wrong - what's the next debug step?
>>>> 
>>>> I greatly appreciate your help!
>>>> 
>>>> Thanks,
>>>> Shivank
>>> 
>>> /Alexander
>>> 
>> 
>> /Alexander
> 
> /Alexander