Skip to content
Closed
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
3 changes: 3 additions & 0 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,9 @@ struct task_struct {
unsigned sched_rt_mutex:1;
#endif

/* Save user-dumpable when mm goes away */
unsigned user_dumpable:1;

/* Bit to tell TOMOYO we're in execve(): */
unsigned in_execve:1;
unsigned in_iowait:1;
Expand Down
4 changes: 2 additions & 2 deletions include/trace/events/rxrpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,6 @@
E_(rxrpc_call_poke_timer_now, "Timer-now")

#define rxrpc_skb_traces \
EM(rxrpc_skb_eaten_by_unshare, "ETN unshare ") \
EM(rxrpc_skb_eaten_by_unshare_nomem, "ETN unshar-nm") \
EM(rxrpc_skb_get_call_rx, "GET call-rx ") \
EM(rxrpc_skb_get_conn_secured, "GET conn-secd") \
EM(rxrpc_skb_get_conn_work, "GET conn-work") \
Expand All @@ -189,6 +187,7 @@
EM(rxrpc_skb_put_purge, "PUT purge ") \
EM(rxrpc_skb_put_purge_oob, "PUT purge-oob") \
EM(rxrpc_skb_put_response, "PUT response ") \
EM(rxrpc_skb_put_response_copy, "PUT resp-cpy ") \
EM(rxrpc_skb_put_rotate, "PUT rotate ") \
EM(rxrpc_skb_put_unknown, "PUT unknown ") \
EM(rxrpc_skb_see_conn_work, "SEE conn-work") \
Expand All @@ -197,6 +196,7 @@
EM(rxrpc_skb_see_recvmsg_oob, "SEE recvm-oob") \
EM(rxrpc_skb_see_reject, "SEE reject ") \
EM(rxrpc_skb_see_rotate, "SEE rotate ") \
EM(rxrpc_skb_see_unshare_nomem, "SEE unshar-nm") \
E_(rxrpc_skb_see_version, "SEE version ")

#define rxrpc_local_traces \
Expand Down
1 change: 1 addition & 0 deletions kernel/exit.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ static void exit_mm(void)
*/
smp_mb__after_spinlock();
local_irq_disable();
current->user_dumpable = (get_dumpable(mm) == SUID_DUMP_USER);
current->mm = NULL;
membarrier_update_current_mm(NULL);
enter_lazy_tlb(mm, current);
Expand Down
22 changes: 16 additions & 6 deletions kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,24 @@ static bool ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
return ns_capable(ns, CAP_SYS_PTRACE);
}

static bool task_still_dumpable(struct task_struct *task, unsigned int mode)
{
struct mm_struct *mm = task->mm;
if (mm) {
if (get_dumpable(mm) == SUID_DUMP_USER)
return true;
return ptrace_has_cap(mm->user_ns, mode);
}

if (task->user_dumpable)
return true;
return ptrace_has_cap(&init_user_ns, mode);
}

/* Returns 0 on success, -errno on denial. */
static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
{
const struct cred *cred = current_cred(), *tcred;
struct mm_struct *mm;
kuid_t caller_uid;
kgid_t caller_gid;

Expand Down Expand Up @@ -337,11 +350,8 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
* Pairs with a write barrier in commit_creds().
*/
smp_rmb();
mm = task->mm;
if (mm &&
((get_dumpable(mm) != SUID_DUMP_USER) &&
!ptrace_has_cap(mm->user_ns, mode)))
return -EPERM;
if (!task_still_dumpable(task, mode))
return -EPERM;

return security_ptrace_access_check(task, mode);
}
Expand Down
3 changes: 2 additions & 1 deletion net/ipv4/esp4.c
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,8 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
nfrags = 1;

goto skip_cow;
} else if (!skb_has_frag_list(skb)) {
} else if (!skb_has_frag_list(skb) &&
!skb_has_shared_frag(skb)) {
nfrags = skb_shinfo(skb)->nr_frags;
nfrags++;

Expand Down
2 changes: 2 additions & 0 deletions net/ipv4/ip_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,8 @@ static int __ip_append_data(struct sock *sk,
if (err < 0)
goto error;
copy = err;
if (!(flags & MSG_NO_SHARED_FRAGS))
skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG;
wmem_alloc_delta += copy;
} else if (!zc) {
int i = skb_shinfo(skb)->nr_frags;
Expand Down
3 changes: 2 additions & 1 deletion net/ipv6/esp6.c
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,8 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
nfrags = 1;

goto skip_cow;
} else if (!skb_has_frag_list(skb)) {
} else if (!skb_has_frag_list(skb) &&
!skb_has_shared_frag(skb)) {
nfrags = skb_shinfo(skb)->nr_frags;
nfrags++;

Expand Down
2 changes: 2 additions & 0 deletions net/ipv6/ip6_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -1765,6 +1765,8 @@ static int __ip6_append_data(struct sock *sk,
if (err < 0)
goto error;
copy = err;
if (!(flags & MSG_NO_SHARED_FRAGS))
skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG;
wmem_alloc_delta += copy;
} else if (!zc) {
int i = skb_shinfo(skb)->nr_frags;
Expand Down
1 change: 0 additions & 1 deletion net/rxrpc/ar-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1486,7 +1486,6 @@ int rxrpc_server_keyring(struct rxrpc_sock *, sockptr_t, int);
void rxrpc_kernel_data_consumed(struct rxrpc_call *, struct sk_buff *);
void rxrpc_new_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_see_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_eaten_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_get_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_free_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_purge_queue(struct sk_buff_head *);
Expand Down
22 changes: 21 additions & 1 deletion net/rxrpc/call_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,27 @@ bool rxrpc_input_call_event(struct rxrpc_call *call)

saw_ack |= sp->hdr.type == RXRPC_PACKET_TYPE_ACK;

rxrpc_input_call_packet(call, skb);
if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA &&
sp->hdr.securityIndex != 0 &&
(skb_cloned(skb) ||
skb_has_frag_list(skb) ||
skb_has_shared_frag(skb))) {
/* Unshare the packet so that it can be
* modified by in-place decryption.
*/
struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);

if (nskb) {
rxrpc_new_skb(nskb, rxrpc_skb_new_unshared);
rxrpc_input_call_packet(call, nskb);
rxrpc_free_skb(nskb, rxrpc_skb_put_call_rx);
} else {
/* OOM - Drop the packet. */
rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem);
}
} else {
rxrpc_input_call_packet(call, skb);
}
rxrpc_free_skb(skb, rxrpc_skb_put_call_rx);
did_receive = true;
}
Expand Down
30 changes: 29 additions & 1 deletion net/rxrpc/conn_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,34 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
rxrpc_notify_socket(call);
}

static int rxrpc_verify_response(struct rxrpc_connection *conn,
struct sk_buff *skb)
{
int ret;

if (skb_cloned(skb) || skb_has_frag_list(skb) ||
skb_has_shared_frag(skb)) {
/* Copy the packet if shared so that we can do in-place
* decryption.
*/
struct sk_buff *nskb = skb_copy(skb, GFP_NOFS);

if (nskb) {
rxrpc_new_skb(nskb, rxrpc_skb_new_unshared);
ret = conn->security->verify_response(conn, nskb);
rxrpc_free_skb(nskb, rxrpc_skb_put_response_copy);
} else {
/* OOM - Drop the packet. */
rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem);
ret = -ENOMEM;
}
} else {
ret = conn->security->verify_response(conn, skb);
}

return ret;
}

/*
* connection-level Rx packet processor
*/
Expand Down Expand Up @@ -270,7 +298,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
}
spin_unlock_irq(&conn->state_lock);

ret = conn->security->verify_response(conn, skb);
ret = rxrpc_verify_response(conn, skb);
if (ret < 0)
return ret;

Expand Down
24 changes: 2 additions & 22 deletions net/rxrpc/io_thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,12 @@ static bool rxrpc_extract_abort(struct sk_buff *skb)
/*
* Process packets received on the local endpoint
*/
static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff *skb)
{
struct rxrpc_connection *conn;
struct sockaddr_rxrpc peer_srx;
struct rxrpc_skb_priv *sp;
struct rxrpc_peer *peer = NULL;
struct sk_buff *skb = *_skb;
bool ret = false;

skb_pull(skb, sizeof(struct udphdr));
Expand Down Expand Up @@ -244,25 +243,6 @@ static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
return rxrpc_bad_message(skb, rxrpc_badmsg_zero_call);
if (sp->hdr.seq == 0)
return rxrpc_bad_message(skb, rxrpc_badmsg_zero_seq);

/* Unshare the packet so that it can be modified for in-place
* decryption.
*/
if (sp->hdr.securityIndex != 0) {
skb = skb_unshare(skb, GFP_ATOMIC);
if (!skb) {
rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare_nomem);
*_skb = NULL;
return just_discard;
}

if (skb != *_skb) {
rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare);
*_skb = skb;
rxrpc_new_skb(skb, rxrpc_skb_new_unshared);
sp = rxrpc_skb(skb);
}
}
break;

case RXRPC_PACKET_TYPE_CHALLENGE:
Expand Down Expand Up @@ -494,7 +474,7 @@ int rxrpc_io_thread(void *data)
switch (skb->mark) {
case RXRPC_SKB_MARK_PACKET:
skb->priority = 0;
if (!rxrpc_input_packet(local, &skb))
if (!rxrpc_input_packet(local, skb))
rxrpc_reject_packet(local, skb);
trace_rxrpc_rx_done(skb->mark, skb->priority);
rxrpc_free_skb(skb, rxrpc_skb_put_input);
Expand Down
9 changes: 0 additions & 9 deletions net/rxrpc/skbuff.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,6 @@ void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace why)
skb_get(skb);
}

/*
* Note the dropping of a ref on a socket buffer by the core.
*/
void rxrpc_eaten_skb(struct sk_buff *skb, enum rxrpc_skb_trace why)
{
int n = atomic_inc_return(&rxrpc_n_rx_skbs);
trace_rxrpc_skb(skb, 0, n, why);
}

/*
* Note the destruction of a socket buffer.
*/
Expand Down
Loading