diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/9p/client.c | 86 | ||||
-rw-r--r-- | net/9p/trans_virtio.c | 34 | ||||
-rw-r--r-- | net/compat.c | 39 | ||||
-rw-r--r-- | net/core/flow_dissector.c | 6 | ||||
-rw-r--r-- | net/ipv6/Kconfig | 1 | ||||
-rw-r--r-- | net/socket.c | 37 |
6 files changed, 72 insertions, 131 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index 8bba0d9cf975..d403085b9ef5 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -550,90 +550,6 @@ out_err: return err; } -/** - * p9_check_zc_errors - check 9p packet for error return and process it - * @c: current client instance - * @req: request to parse and check for error conditions - * @uidata: external buffer containing error - * @in_hdrlen: Size of response protocol buffer. - * - * returns error code if one is discovered, otherwise returns 0 - * - * this will have to be more complicated if we have multiple - * error packet types - */ - -static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req, - struct iov_iter *uidata, int in_hdrlen) -{ - int err; - int ecode; - s8 type; - char *ename = NULL; - - err = p9_parse_header(&req->rc, NULL, &type, NULL, 0); - /* dump the response from server - * This should be after parse_header which poplulate pdu_fcall. - */ - trace_9p_protocol_dump(c, &req->rc); - if (err) { - p9_debug(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); - return err; - } - - if (type != P9_RERROR && type != P9_RLERROR) - return 0; - - if (!p9_is_proto_dotl(c)) { - /* Error is reported in string format */ - int len; - /* 7 = header size for RERROR; */ - int inline_len = in_hdrlen - 7; - - len = req->rc.size - req->rc.offset; - if (len > (P9_ZC_HDR_SZ - 7)) { - err = -EFAULT; - goto out_err; - } - - ename = &req->rc.sdata[req->rc.offset]; - if (len > inline_len) { - /* We have error in external buffer */ - if (!copy_from_iter_full(ename + inline_len, - len - inline_len, uidata)) { - err = -EFAULT; - goto out_err; - } - } - ename = NULL; - err = p9pdu_readf(&req->rc, c->proto_version, "s?d", - &ename, &ecode); - if (err) - goto out_err; - - if (p9_is_proto_dotu(c) && ecode < 512) - err = -ecode; - - if (!err) { - err = p9_errstr2errno(ename, strlen(ename)); - - p9_debug(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", - -ecode, ename); - } - kfree(ename); - } else { - err = p9pdu_readf(&req->rc, c->proto_version, "d", &ecode); - err = -ecode; - - p9_debug(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); - } - return err; - -out_err: - p9_debug(P9_DEBUG_ERROR, "couldn't parse error%d\n", err); - return err; -} - static struct p9_req_t * p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); @@ -874,7 +790,7 @@ recalc_sigpending: if (err < 0) goto reterr; - err = p9_check_zc_errors(c, req, uidata, in_hdrlen); + err = p9_check_errors(c, req); trace_9p_client_res(c, type, req->rc.tag, err); if (!err) return req; diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index b24a4fb0f0a2..2a210c2f8e40 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -377,6 +377,35 @@ static int p9_get_mapped_pages(struct virtio_chan *chan, } } +static void handle_rerror(struct p9_req_t *req, int in_hdr_len, + size_t offs, struct page **pages) +{ + unsigned size, n; + void *to = req->rc.sdata + in_hdr_len; + + // Fits entirely into the static data? Nothing to do. + if (req->rc.size < in_hdr_len) + return; + + // Really long error message? Tough, truncate the reply. Might get + // rejected (we can't be arsed to adjust the size encoded in header, + // or string size for that matter), but it wouldn't be anything valid + // anyway. + if (unlikely(req->rc.size > P9_ZC_HDR_SZ)) + req->rc.size = P9_ZC_HDR_SZ; + + // data won't span more than two pages + size = req->rc.size - in_hdr_len; + n = PAGE_SIZE - offs; + if (size > n) { + memcpy_from_page(to, *pages++, offs, n); + offs = 0; + to += n; + size -= n; + } + memcpy_from_page(to, *pages, offs, size); +} + /** * p9_virtio_zc_request - issue a zero copy request * @client: client instance issuing the request @@ -503,6 +532,11 @@ req_retry_pinned: kicked = 1; p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n"); err = wait_event_killable(req->wq, req->status >= REQ_STATUS_RCVD); + // RERROR needs reply (== error string) in static data + if (req->status == REQ_STATUS_RCVD && + unlikely(req->rc.sdata[4] == P9_RERROR)) + handle_rerror(req, in_hdr_len, offs, in_pages); + /* * Non kernel buffers are pinned, unpin them */ diff --git a/net/compat.c b/net/compat.c index 6cd2e7683dd0..fe9be3c56ef7 100644 --- a/net/compat.c +++ b/net/compat.c @@ -34,20 +34,15 @@ #include <net/compat.h> int __get_compat_msghdr(struct msghdr *kmsg, - struct compat_msghdr __user *umsg, - struct sockaddr __user **save_addr, - compat_uptr_t *ptr, compat_size_t *len) + struct compat_msghdr *msg, + struct sockaddr __user **save_addr) { - struct compat_msghdr msg; ssize_t err; - if (copy_from_user(&msg, umsg, sizeof(*umsg))) - return -EFAULT; - - kmsg->msg_flags = msg.msg_flags; - kmsg->msg_namelen = msg.msg_namelen; + kmsg->msg_flags = msg->msg_flags; + kmsg->msg_namelen = msg->msg_namelen; - if (!msg.msg_name) + if (!msg->msg_name) kmsg->msg_namelen = 0; if (kmsg->msg_namelen < 0) @@ -57,15 +52,15 @@ int __get_compat_msghdr(struct msghdr *kmsg, kmsg->msg_namelen = sizeof(struct sockaddr_storage); kmsg->msg_control_is_user = true; - kmsg->msg_control_user = compat_ptr(msg.msg_control); - kmsg->msg_controllen = msg.msg_controllen; + kmsg->msg_control_user = compat_ptr(msg->msg_control); + kmsg->msg_controllen = msg->msg_controllen; if (save_addr) - *save_addr = compat_ptr(msg.msg_name); + *save_addr = compat_ptr(msg->msg_name); - if (msg.msg_name && kmsg->msg_namelen) { + if (msg->msg_name && kmsg->msg_namelen) { if (!save_addr) { - err = move_addr_to_kernel(compat_ptr(msg.msg_name), + err = move_addr_to_kernel(compat_ptr(msg->msg_name), kmsg->msg_namelen, kmsg->msg_name); if (err < 0) @@ -76,13 +71,11 @@ int __get_compat_msghdr(struct msghdr *kmsg, kmsg->msg_namelen = 0; } - if (msg.msg_iovlen > UIO_MAXIOV) + if (msg->msg_iovlen > UIO_MAXIOV) return -EMSGSIZE; kmsg->msg_iocb = NULL; kmsg->msg_ubuf = NULL; - *ptr = msg.msg_iov; - *len = msg.msg_iovlen; return 0; } @@ -91,15 +84,17 @@ int get_compat_msghdr(struct msghdr *kmsg, struct sockaddr __user **save_addr, struct iovec **iov) { - compat_uptr_t ptr; - compat_size_t len; + struct compat_msghdr msg; ssize_t err; - err = __get_compat_msghdr(kmsg, umsg, save_addr, &ptr, &len); + if (copy_from_user(&msg, umsg, sizeof(*umsg))) + return -EFAULT; + + err = __get_compat_msghdr(kmsg, &msg, save_addr); if (err) return err; - err = import_iovec(save_addr ? READ : WRITE, compat_ptr(ptr), len, + err = import_iovec(save_addr ? READ : WRITE, compat_ptr(msg.msg_iov), msg.msg_iovlen, UIO_FASTIOV, iov, &kmsg->msg_iter); return err < 0 ? err : 0; } diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 237d396b6e41..764c4cb3fe8f 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -895,9 +895,9 @@ bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, return result == BPF_OK; } -static bool is_pppoe_ses_hdr_valid(struct pppoe_hdr hdr) +static bool is_pppoe_ses_hdr_valid(const struct pppoe_hdr *hdr) { - return hdr.ver == 1 && hdr.type == 1 && hdr.code == 0; + return hdr->ver == 1 && hdr->type == 1 && hdr->code == 0; } /** @@ -1227,7 +1227,7 @@ proto_again: break; } - if (!is_pppoe_ses_hdr_valid(hdr->hdr)) { + if (!is_pppoe_ses_hdr_valid(&hdr->hdr)) { fdret = FLOW_DISSECT_RET_OUT_BAD; break; } diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index bf2e5e5fe142..658bfed1df8b 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -7,6 +7,7 @@ menuconfig IPV6 tristate "The IPv6 protocol" default y + select CRYPTO_LIB_SHA1 help Support for IP version 6 (IPv6). diff --git a/net/socket.c b/net/socket.c index b6bd4cf44d3f..9b27c5e4e5ba 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2356,25 +2356,20 @@ struct used_address { unsigned int name_len; }; -int __copy_msghdr_from_user(struct msghdr *kmsg, - struct user_msghdr __user *umsg, - struct sockaddr __user **save_addr, - struct iovec __user **uiov, size_t *nsegs) +int __copy_msghdr(struct msghdr *kmsg, + struct user_msghdr *msg, + struct sockaddr __user **save_addr) { - struct user_msghdr msg; ssize_t err; - if (copy_from_user(&msg, umsg, sizeof(*umsg))) - return -EFAULT; - kmsg->msg_control_is_user = true; kmsg->msg_get_inq = 0; - kmsg->msg_control_user = msg.msg_control; - kmsg->msg_controllen = msg.msg_controllen; - kmsg->msg_flags = msg.msg_flags; + kmsg->msg_control_user = msg->msg_control; + kmsg->msg_controllen = msg->msg_controllen; + kmsg->msg_flags = msg->msg_flags; - kmsg->msg_namelen = msg.msg_namelen; - if (!msg.msg_name) + kmsg->msg_namelen = msg->msg_namelen; + if (!msg->msg_name) kmsg->msg_namelen = 0; if (kmsg->msg_namelen < 0) @@ -2384,11 +2379,11 @@ int __copy_msghdr_from_user(struct msghdr *kmsg, kmsg->msg_namelen = sizeof(struct sockaddr_storage); if (save_addr) - *save_addr = msg.msg_name; + *save_addr = msg->msg_name; - if (msg.msg_name && kmsg->msg_namelen) { + if (msg->msg_name && kmsg->msg_namelen) { if (!save_addr) { - err = move_addr_to_kernel(msg.msg_name, + err = move_addr_to_kernel(msg->msg_name, kmsg->msg_namelen, kmsg->msg_name); if (err < 0) @@ -2399,13 +2394,11 @@ int __copy_msghdr_from_user(struct msghdr *kmsg, kmsg->msg_namelen = 0; } - if (msg.msg_iovlen > UIO_MAXIOV) + if (msg->msg_iovlen > UIO_MAXIOV) return -EMSGSIZE; kmsg->msg_iocb = NULL; kmsg->msg_ubuf = NULL; - *uiov = msg.msg_iov; - *nsegs = msg.msg_iovlen; return 0; } @@ -2417,8 +2410,10 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, struct user_msghdr msg; ssize_t err; - err = __copy_msghdr_from_user(kmsg, umsg, save_addr, &msg.msg_iov, - &msg.msg_iovlen); + if (copy_from_user(&msg, umsg, sizeof(*umsg))) + return -EFAULT; + + err = __copy_msghdr(kmsg, &msg, save_addr); if (err) return err; |