Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,7 @@ static int vmw_event_fence_action_create(struct drm_file *file_priv,
}

event->event.base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
event->event.base.length = sizeof(*event);
event->event.base.length = sizeof(event->event);
event->event.user_data = user_data;

ret = drm_event_reserve_init(dev, file_priv, &event->base, &event->event.base);
Expand Down
2 changes: 1 addition & 1 deletion fs/locks.c
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,7 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request,
locks_wake_up_blocks(left);
}
out:
trace_posix_lock_inode(inode, request, error);
spin_unlock(&ctx->flc_lock);
percpu_up_read(&file_rwsem);
/*
Expand All @@ -1237,7 +1238,6 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request,
if (new_fl2)
locks_free_lock(new_fl2);
locks_dispose_list(&dispose);
trace_posix_lock_inode(inode, request, error);

return error;
}
Expand Down
69 changes: 47 additions & 22 deletions kernel/events/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1806,31 +1806,34 @@ static inline void perf_event__state_init(struct perf_event *event)
PERF_EVENT_STATE_INACTIVE;
}

static void __perf_event_read_size(struct perf_event *event, int nr_siblings)
static int __perf_event_read_size(u64 read_format, int nr_siblings)
{
int entry = sizeof(u64); /* value */
int size = 0;
int nr = 1;

if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
size += sizeof(u64);

if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
size += sizeof(u64);

if (event->attr.read_format & PERF_FORMAT_ID)
if (read_format & PERF_FORMAT_ID)
entry += sizeof(u64);

if (event->attr.read_format & PERF_FORMAT_LOST)
if (read_format & PERF_FORMAT_LOST)
entry += sizeof(u64);

if (event->attr.read_format & PERF_FORMAT_GROUP) {
if (read_format & PERF_FORMAT_GROUP) {
nr += nr_siblings;
size += sizeof(u64);
}

size += entry * nr;
event->read_size = size;
/*
* Since perf_event_validate_size() limits this to 16k and inhibits
* adding more siblings, this will never overflow.
*/
return size + nr * entry;
}

static void __perf_event_header_size(struct perf_event *event, u64 sample_type)
Expand Down Expand Up @@ -1880,8 +1883,9 @@ static void __perf_event_header_size(struct perf_event *event, u64 sample_type)
*/
static void perf_event__header_size(struct perf_event *event)
{
__perf_event_read_size(event,
event->group_leader->nr_siblings);
event->read_size =
__perf_event_read_size(event->attr.read_format,
event->group_leader->nr_siblings);
__perf_event_header_size(event, event->attr.sample_type);
}

Expand Down Expand Up @@ -1912,23 +1916,44 @@ static void perf_event__id_header_size(struct perf_event *event)
event->id_header_size = size;
}

/*
* Check that adding an event to the group does not result in anybody
* overflowing the 64k event limit imposed by the output buffer.
*
* Specifically, check that the read_size for the event does not exceed 16k,
* read_size being the one term that grows with groups size. Since read_size
* depends on per-event read_format, also (re)check the existing events.
*
* This leaves 48k for the constant size fields and things like callchains,
* branch stacks and register sets.
*/
static bool perf_event_validate_size(struct perf_event *event)
{
/*
* The values computed here will be over-written when we actually
* attach the event.
*/
__perf_event_read_size(event, event->group_leader->nr_siblings + 1);
__perf_event_header_size(event, event->attr.sample_type & ~PERF_SAMPLE_READ);
perf_event__id_header_size(event);
struct perf_event *sibling, *group_leader = event->group_leader;

if (__perf_event_read_size(event->attr.read_format,
group_leader->nr_siblings + 1) > 16*1024)
return false;

if (__perf_event_read_size(group_leader->attr.read_format,
group_leader->nr_siblings + 1) > 16*1024)
return false;

/*
* Sum the lot; should not exceed the 64k limit we have on records.
* Conservative limit to allow for callchains and other variable fields.
* When creating a new group leader, group_leader->ctx is initialized
* after the size has been validated, but we cannot safely use
* for_each_sibling_event() until group_leader->ctx is set. A new group
* leader cannot have any siblings yet, so we can safely skip checking
* the non-existent siblings.
*/
if (event->read_size + event->header_size +
event->id_header_size + sizeof(struct perf_event_header) >= 16*1024)
return false;
if (event == group_leader)
return true;

for_each_sibling_event(sibling, group_leader) {
if (__perf_event_read_size(sibling->attr.read_format,
group_leader->nr_siblings + 1) > 16*1024)
return false;
}

return true;
}
Expand Down
6 changes: 6 additions & 0 deletions net/bridge/netfilter/ebtables.c
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,8 @@ static int do_replace(struct net *net, sockptr_t arg, unsigned int len)
struct ebt_table_info *newinfo;
struct ebt_replace tmp;

if (len < sizeof(tmp))
return -EINVAL;
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;

Expand Down Expand Up @@ -1337,6 +1339,8 @@ static int update_counters(struct net *net, sockptr_t arg, unsigned int len)
{
struct ebt_replace hlp;

if (len < sizeof(hlp))
return -EINVAL;
if (copy_from_sockptr(&hlp, arg, sizeof(hlp)))
return -EFAULT;

Expand Down Expand Up @@ -2267,6 +2271,8 @@ static int compat_update_counters(struct net *net, sockptr_t arg,
{
struct compat_ebt_replace hlp;

if (len < sizeof(hlp))
return -EINVAL;
if (copy_from_sockptr(&hlp, arg, sizeof(hlp)))
return -EFAULT;

Expand Down
13 changes: 10 additions & 3 deletions net/core/net_namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,15 @@ DEFINE_COOKIE(net_cookie);

static struct net_generic *net_alloc_generic(void)
{
unsigned int gen_ptrs = READ_ONCE(max_gen_ptrs);
unsigned int generic_size;
struct net_generic *ng;
unsigned int generic_size = offsetof(struct net_generic, ptr[max_gen_ptrs]);

generic_size = offsetof(struct net_generic, ptr[gen_ptrs]);

ng = kzalloc(generic_size, GFP_KERNEL);
if (ng)
ng->s.len = max_gen_ptrs;
ng->s.len = gen_ptrs;

return ng;
}
Expand Down Expand Up @@ -1210,7 +1213,11 @@ static int register_pernet_operations(struct list_head *list,
if (error < 0)
return error;
*ops->id = error;
max_gen_ptrs = max(max_gen_ptrs, *ops->id + 1);
/* This does not require READ_ONCE as writers already hold
* pernet_ops_rwsem. But WRITE_ONCE is needed to protect
* net_alloc_generic.
*/
WRITE_ONCE(max_gen_ptrs, max(max_gen_ptrs, *ops->id + 1));
}
error = __register_pernet_operations(list, ops);
if (error) {
Expand Down
8 changes: 8 additions & 0 deletions net/ipv4/netfilter/arp_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,8 @@ static int do_replace(struct net *net, sockptr_t arg, unsigned int len)
void *loc_cpu_entry;
struct arpt_entry *iter;

if (len < sizeof(tmp))
return -EINVAL;
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;

Expand All @@ -963,6 +965,8 @@ static int do_replace(struct net *net, sockptr_t arg, unsigned int len)
return -ENOMEM;
if (tmp.num_counters == 0)
return -EINVAL;
if ((u64)len < (u64)tmp.size + sizeof(tmp))
return -EINVAL;

tmp.name[sizeof(tmp.name)-1] = 0;

Expand Down Expand Up @@ -1253,6 +1257,8 @@ static int compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
void *loc_cpu_entry;
struct arpt_entry *iter;

if (len < sizeof(tmp))
return -EINVAL;
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;

Expand All @@ -1261,6 +1267,8 @@ static int compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
return -ENOMEM;
if (tmp.num_counters == 0)
return -EINVAL;
if ((u64)len < (u64)tmp.size + sizeof(tmp))
return -EINVAL;

tmp.name[sizeof(tmp.name)-1] = 0;

Expand Down
8 changes: 8 additions & 0 deletions net/ipv4/netfilter/ip_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,8 @@ do_replace(struct net *net, sockptr_t arg, unsigned int len)
void *loc_cpu_entry;
struct ipt_entry *iter;

if (len < sizeof(tmp))
return -EINVAL;
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;

Expand All @@ -1118,6 +1120,8 @@ do_replace(struct net *net, sockptr_t arg, unsigned int len)
return -ENOMEM;
if (tmp.num_counters == 0)
return -EINVAL;
if ((u64)len < (u64)tmp.size + sizeof(tmp))
return -EINVAL;

tmp.name[sizeof(tmp.name)-1] = 0;

Expand Down Expand Up @@ -1494,6 +1498,8 @@ compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
void *loc_cpu_entry;
struct ipt_entry *iter;

if (len < sizeof(tmp))
return -EINVAL;
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;

Expand All @@ -1502,6 +1508,8 @@ compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
return -ENOMEM;
if (tmp.num_counters == 0)
return -EINVAL;
if ((u64)len < (u64)tmp.size + sizeof(tmp))
return -EINVAL;

tmp.name[sizeof(tmp.name)-1] = 0;

Expand Down
8 changes: 7 additions & 1 deletion net/ipv4/tcp_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
if (tcptw->tw_ts_recent_stamp &&
(!twp || (reuse && time_after32(ktime_get_seconds(),
tcptw->tw_ts_recent_stamp)))) {
/* inet_twsk_hashdance() sets sk_refcnt after putting twsk
* and releasing the bucket lock.
*/
if (unlikely(!refcount_inc_not_zero(&sktw->sk_refcnt)))
return 0;

/* In case of repair and re-using TIME-WAIT sockets we still
* want to be sure that it is safe as above but honor the
* sequence numbers and time stamps set as part of the repair
Expand All @@ -171,7 +177,7 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
tp->rx_opt.ts_recent = tcptw->tw_ts_recent;
tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp;
}
sock_hold(sktw);

return 1;
}

Expand Down
8 changes: 8 additions & 0 deletions net/ipv6/netfilter/ip6_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,8 @@ do_replace(struct net *net, sockptr_t arg, unsigned int len)
void *loc_cpu_entry;
struct ip6t_entry *iter;

if (len < sizeof(tmp))
return -EINVAL;
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;

Expand All @@ -1135,6 +1137,8 @@ do_replace(struct net *net, sockptr_t arg, unsigned int len)
return -ENOMEM;
if (tmp.num_counters == 0)
return -EINVAL;
if ((u64)len < (u64)tmp.size + sizeof(tmp))
return -EINVAL;

tmp.name[sizeof(tmp.name)-1] = 0;

Expand Down Expand Up @@ -1503,6 +1507,8 @@ compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
void *loc_cpu_entry;
struct ip6t_entry *iter;

if (len < sizeof(tmp))
return -EINVAL;
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;

Expand All @@ -1511,6 +1517,8 @@ compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
return -ENOMEM;
if (tmp.num_counters == 0)
return -EINVAL;
if ((u64)len < (u64)tmp.size + sizeof(tmp))
return -EINVAL;

tmp.name[sizeof(tmp.name)-1] = 0;

Expand Down
21 changes: 7 additions & 14 deletions net/ipv6/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -5355,26 +5355,20 @@ static int ip6_route_multipath_add(struct fib6_config *cfg,
err_nh = NULL;
list_for_each_entry(nh, &rt6_nh_list, next) {
err = __ip6_ins_rt(nh->fib6_info, info, extack);
fib6_info_release(nh->fib6_info);

if (!err) {
/* save reference to last route successfully inserted */
rt_last = nh->fib6_info;

/* save reference to first route for notification */
if (!rt_notif)
rt_notif = nh->fib6_info;
}

/* nh->fib6_info is used or freed at this point, reset to NULL*/
nh->fib6_info = NULL;
if (err) {
if (replace && nhn)
NL_SET_ERR_MSG_MOD(extack,
"multipath route replace failed (check consistency of installed routes)");
err_nh = nh;
goto add_errout;
}
/* save reference to last route successfully inserted */
rt_last = nh->fib6_info;

/* save reference to first route for notification */
if (!rt_notif)
rt_notif = nh->fib6_info;

/* Because each route is added like a single route we remove
* these flags after the first nexthop: if there is a collision,
Expand Down Expand Up @@ -5435,8 +5429,7 @@ static int ip6_route_multipath_add(struct fib6_config *cfg,

cleanup:
list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
if (nh->fib6_info)
fib6_info_release(nh->fib6_info);
fib6_info_release(nh->fib6_info);
list_del(&nh->next);
kfree(nh);
}
Expand Down
Loading