We cannot call copyout() while in a net epoch section, unless the user
memory is wired. Use the global ifnet lock to synchronize access to the
list instead.
Reported by: emaste
Differential D57154
net: Fix handling of unmapped user pages in if_getgroup() Authored by markj on Thu, May 21, 7:15 PM. Tags None Referenced Files
Details
Diff Detail
Event TimelineComment Actions LGTM. Maybe this would be a bit clearer as if (ifgr->ifgr_len == 0) {
NET_EPOCH_ENTER();
CQ_STAILQ_FOREACH(...
NET_EPOCH_EXIT();
return (0);
}
vslock(...)i.e. handle the len == 0 determine the size case first? Comment Actions Thanks, that's more clear to me. We are already assigning len = ifgr->ifgr_len; so we could move it up and use it in the vslock call IMO.
Comment Actions The ioctl path shall not use the epoch. The list is protected by IFNET_WLOCK(). Ideally the IFNET_WLOCK should become a sleepable lock. A temporary solution would be to keep IFNET_WLOCK() as is and allocate a temporary buffer to fill, then unlock and do copyout from this buffer. To make buffer size guessing easier we can track number of members in the V_ifg_head and try to allocate this size. Comment Actions Why? What about the sysctl path?
The global ifnet lock is already a sleepable lock, so we can just wrap the whole function with it. Technically the list is protected by the in_addr lock, which is non-sleepable, but in practice all modifications to the list are done under the ifnet lock. Allocating a separate buffer is racy and error-prone, I don't really like that approach. While I'm generally ok with reducing use of net_epoch in the control path:
so I don't see why it's so necessary to use a lock here. Comment Actions To avoid patches like this :) So that we don't need to do virtual memory tricks for such a simple operation as getting list of names from kernel. In general changing and reading configuration from userland should be synchronized by locks. Of course, simple cases like grabbing a single integer via sysctl may use epoch.
The list already is epoch safe, isn't it? Does pf need to pull the entire contents of the list on the data path or just do a match of a name against the list?
Common at what rate? Few events per second I'd guess. As long as the data path doesn't acquire the lock, there is nothing wrong for SIOCGIFGROUP to acquire the lock. Most network configuration ioctls acquire locks. Of course acquiring per-interface lock is better than global one and looks like in this case it is possible. Comment Actions We do it regularly, usually it's spelled sysctl_wire_old_buffer().
epoch is for synchronizing access to objects with finite lifetimes, there's no reason at all to use it for reading an integer.
I am not sure what exactly it is doing. Comment Actions
Yes, that is perfect. I think the introduction of net epoch makes it a bit harder to maintain. Traditional lock based synchronization is much easier to understand.
Compared to the data path, the ioctl is typically a low frequent operation. The mind to serialize the ioctl operation comes while I was working on the ifnet detach / vmove racing issue. Acquiring a ( global / per-interface ) lock shall not hurt the performance.
It is not about necessary, but a simpler programming model to ease the maintain, from the design perspective. | ||||||||||||||||||||