From: Junhao He hejunhao3@huawei.com
driver inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5EZY2
------------------------------------------------------------------
In FIFO mode, when the state of sink buffer is full, the sink device will continuously backpressures the ETM, so that the ETM cannot switch to the idle state. In this case, the WFx instruction cannot be executed because the CPU detects that the ETM is not in the idle state which that will cause CPU hung. We workaround this issue on HiSilicon ETM by setting bit 13 of TRCAUXCTLR which is used to indicate that the ETM is in the idle state.
The call trace is shown below: rcu: INFO: rcu_sched detected stalls on CPUs/tasks: rcu: 10-...0: (1 ticks this GP) idle=5b6/1/0x4000000000000000 softirq=12309/12318 fqs=114196 (detected by 67, t=330041 jiffies, g=309253, q=453663) Task dump for CPU 10: task:ksoftirqd/10 state:R running task stack: 0 pid: 64 ppid: 2 flags:0x0000000a Call trace: __switch_to+0xbc/0xfc irqtime_account_irq+0x58/0xc4 __do_softirq+0x6c/0x358 run_ksoftirqd+0x68/0x90 smpboot_thread_fn+0x15c/0x1a0 kthread+0x108/0x13c ret_from_fork+0x10/0x18 watchdog: BUG: soft lockup - CPU#35 stuck for 22s! [bash:133345] ... Call trace: smp_call_function_single+0x178/0x190 etm4_disable_sysfs+0x74/0xfc [coresight_etm4x] etm4_disable+0x6c/0x70 [coresight_etm4x] coresight_disable_source+0x7c/0xa0 [coresight] coresight_disable+0x6c/0x13c [coresight] enable_source_store+0x88/0xa0 [coresight] dev_attr_store+0x20/0x34 sysfs_kf_write+0x4c/0x5c kernfs_fop_write_iter+0x130/0x1c0 new_sync_write+0xec/0x18c vfs_write+0x214/0x2ac ksys_write+0x70/0xfc __arm64_sys_write+0x24/0x30 el0_svc_common.constprop.0+0x7c/0x1bc do_el0_svc+0x2c/0x94 el0_svc+0x20/0x30 el0_sync_handler+0xb0/0xb4 el0_sync+0x160/0x180
Signed-off-by: Qi Liu liuqi115@huawei.com Signed-off-by: Junhao He hejunhao3@huawei.com Reviewed-by: Jay Fang f.fangjian@huawei.com Acked-by: Xie XiuQi xiexiuqi@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../coresight/coresight-etm4x-core.c | 37 +++++++++++++++---- drivers/hwtracing/coresight/coresight-etm4x.h | 1 + 2 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index d4d9c8bb88ca..881da29cbd5a 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -116,8 +116,10 @@ struct etm4_enable_arg { #define HISI_HIP08_CORE_COMMIT_LVL_1 0b01 #define HISI_HIP08_CORE_COMMIT_REG sys_reg(3, 1, 15, 2, 5)
+#define HISI_HIP08_AUXCTRL_CHICKEN_BIT BIT(13) + struct etm4_arch_features { - void (*arch_callback)(bool enable); + void (*arch_callback)(void *info); };
static bool etm4_hisi_match_pid(unsigned int id) @@ -125,8 +127,9 @@ static bool etm4_hisi_match_pid(unsigned int id) return (id & ETM4_AMBA_MASK) == HISI_HIP08_AMBA_ID; }
-static void etm4_hisi_config_core_commit(bool enable) +static void etm4_hisi_config_core_commit(void *info) { + bool enable = *(bool *)info; u8 commit = enable ? HISI_HIP08_CORE_COMMIT_LVL_1 : HISI_HIP08_CORE_COMMIT_FULL; u64 val; @@ -143,48 +146,67 @@ static void etm4_hisi_config_core_commit(bool enable) write_sysreg_s(val, HISI_HIP08_CORE_COMMIT_REG); }
+static void etm4_hisi_config_auxctrlr(void *info) +{ + struct etmv4_drvdata *drvdata = info; + + /* Switch the ETM to idle state */ + writel_relaxed(HISI_HIP08_AUXCTRL_CHICKEN_BIT, drvdata->base + TRCAUXCTLR); +} + static struct etm4_arch_features etm4_features[] = { [ETM4_IMPDEF_HISI_CORE_COMMIT] = { .arch_callback = etm4_hisi_config_core_commit, }, + [ETM4_IMPDEF_HISI_SET_AUXCTRLR] = { + .arch_callback = etm4_hisi_config_auxctrlr, + }, {}, };
static void etm4_enable_arch_specific(struct etmv4_drvdata *drvdata) { struct etm4_arch_features *ftr; + bool enable = true; int bit;
for_each_set_bit(bit, drvdata->arch_features, ETM4_IMPDEF_FEATURE_MAX) { ftr = &etm4_features[bit];
- if (ftr->arch_callback) - ftr->arch_callback(true); + if (bit == ETM4_IMPDEF_HISI_CORE_COMMIT && ftr->arch_callback) + ftr->arch_callback(&enable); + + if (bit == ETM4_IMPDEF_HISI_SET_AUXCTRLR && ftr->arch_callback) + ftr->arch_callback(drvdata); } }
static void etm4_disable_arch_specific(struct etmv4_drvdata *drvdata) { struct etm4_arch_features *ftr; + bool enable = false; int bit;
for_each_set_bit(bit, drvdata->arch_features, ETM4_IMPDEF_FEATURE_MAX) { ftr = &etm4_features[bit];
- if (ftr->arch_callback) - ftr->arch_callback(false); + if (bit == ETM4_IMPDEF_HISI_CORE_COMMIT && ftr->arch_callback) + ftr->arch_callback(&enable); } }
static void etm4_check_arch_features(struct etmv4_drvdata *drvdata, unsigned int id) { - if (etm4_hisi_match_pid(id)) + if (etm4_hisi_match_pid(id)) { set_bit(ETM4_IMPDEF_HISI_CORE_COMMIT, drvdata->arch_features); + set_bit(ETM4_IMPDEF_HISI_SET_AUXCTRLR, drvdata->arch_features); + } } #else static void etm4_enable_arch_specific(struct etmv4_drvdata *drvdata) { + writel_relaxed(0x0, drvdata->base + TRCAUXCTLR); }
static void etm4_disable_arch_specific(struct etmv4_drvdata *drvdata) @@ -223,7 +245,6 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata) writel_relaxed(config->pe_sel, drvdata->base + TRCPROCSELR); writel_relaxed(config->cfg, drvdata->base + TRCCONFIGR); /* nothing specific implemented */ - writel_relaxed(0x0, drvdata->base + TRCAUXCTLR); writel_relaxed(config->eventctrl0, drvdata->base + TRCEVENTCTL0R); writel_relaxed(config->eventctrl1, drvdata->base + TRCEVENTCTL1R); if (drvdata->stallctl) diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index 3dd3e0633328..ef9d7365c2da 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -206,6 +206,7 @@
enum etm_impdef_type { ETM4_IMPDEF_HISI_CORE_COMMIT, + ETM4_IMPDEF_HISI_SET_AUXCTRLR, ETM4_IMPDEF_FEATURE_MAX, };
From: Zhihao Cheng chengzhihao1@huawei.com
hulk inclusion category: bugfix bugzilla: 187369, https://gitee.com/openeuler/kernel/issues/I5K66O CVE: NA
--------------------------------
Following process triggers an use-after-free problem while iterating every process's fs:
main fd = setup_iouring fork => main' // task->fs->users = 1 submit(fd, STATX, async) id->fs = current->fs req->work.identity = id io_submit_sqes ... io_grab_identity id = req->work.identity id->fs->users++ // fs->users = 2
io_wqe_worker current->fs = work->identity->fs io_req_clean_work fs = req->work.identity->fs --fs->users // fs->user = 1
main' exit exit_fs --fs->users // fs->user = 0 free_fs_struct(fs) // FREE fs
pivot_root chroot_fs_refs do_each_thread(g, p) { fs = p->fs // io_wqe_worker->fs if (fs) spin_lock(&fs->lock) // UAF! }
io_wqe_worker io_worker_exit __io_worker_unuse if (current->fs != worker->restore_fs) current->fs = worker->restore_fs
Task's fs_struct is used in do_work() and destroyed in free_work(), this problem can be fixed by switching io_wqe_worker's fs before releasing request.
Signed-off-by: Zhihao Cheng chengzhihao1@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- fs/io-wq.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/fs/io-wq.c b/fs/io-wq.c index 3d5fc76b92d0..56d00f31003b 100644 --- a/fs/io-wq.c +++ b/fs/io-wq.c @@ -578,6 +578,8 @@ static void io_worker_handle_work(struct io_worker *worker) linked = NULL; } io_assign_current_work(worker, work); + if (current->fs != worker->restore_fs) + current->fs = worker->restore_fs; wq->free_work(old_work);
if (linked)
From: Li Lingfeng lilingfeng3@huawei.com
hulk inclusion category: bugfix bugzilla: 187387, https://gitee.com/openeuler/kernel/issues/I5KTEM CVE: NA
--------------------------------
When we need to create a private copy of io_identity, we will get the use of current task's private structs, whitch means we should increase their reference counts. If we have grabed some other structs before, we should drop them and clear related flags. Otherwise, leak of old structs and uaf of new structs may occur.
Signed-off-by: Li Lingfeng lilingfeng3@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- fs/io_uring.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
diff --git a/fs/io_uring.c b/fs/io_uring.c index 23afe8fd0156..dee1d15ba52c 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -1357,6 +1357,47 @@ static bool io_identity_cow(struct io_kiocb *req) return true; }
+static void io_drop_identity(struct io_kiocb *req) +{ + struct io_identity *id = req->work.identity; + + if (req->work.flags & IO_WQ_WORK_MM) { + mmdrop(id->mm); + req->work.flags &= ~IO_WQ_WORK_MM; + } +#ifdef CONFIG_BLK_CGROUP + if (req->work.flags & IO_WQ_WORK_BLKCG) { + css_put(id->blkcg_css); + req->work.flags &= ~IO_WQ_WORK_BLKCG; + } +#endif + if (req->work.flags & IO_WQ_WORK_CREDS) { + put_cred(id->creds); + req->work.flags &= ~IO_WQ_WORK_CREDS; + } + if (req->work.flags & IO_WQ_WORK_FILES) { + put_files_struct(req->work.identity->files); + put_nsproxy(req->work.identity->nsproxy); + req->work.flags &= ~IO_WQ_WORK_FILES; + } + if (req->work.flags & IO_WQ_WORK_CANCEL) + req->work.flags &= ~IO_WQ_WORK_CANCEL; + if (req->work.flags & IO_WQ_WORK_FS) { + struct fs_struct *fs = id->fs; + + spin_lock(&id->fs->lock); + if (--fs->users) + fs = NULL; + spin_unlock(&id->fs->lock); + + if (fs) + free_fs_struct(fs); + req->work.flags &= ~IO_WQ_WORK_FS; + } + if (req->work.flags & IO_WQ_WORK_FSIZE) + req->work.flags &= ~IO_WQ_WORK_FSIZE; +} + static bool io_grab_identity(struct io_kiocb *req) { const struct io_op_def *def = &io_op_defs[req->opcode]; @@ -1462,6 +1503,7 @@ static void io_prep_async_work(struct io_kiocb *req) if (io_grab_identity(req)) return;
+ io_drop_identity(req); if (!io_identity_cow(req)) return;
From: Jens Axboe axboe@kernel.dk
stable inclusion from stable-v5.10.125 commit df3f3bb5059d20ef094d6b2f0256c4bf4127a859 category: bugfix bugzilla: 187376, https://gitee.com/src-openeuler/kernel/issues/I5IM3T CVE: CVE-2022-2327
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Any read/write should grab current->nsproxy, denoted by IO_WQ_WORK_FILES as it refers to current->files as well, and connect and recv/recvmsg, send/sendmsg should grab current->fs which is denoted by IO_WQ_WORK_FS.
No upstream commit exists for this issue.
Reported-by: Bing-Jhong Billy Jheng billy@starlabs.sg Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Xiu Jianfeng xiujianfeng@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- fs/io_uring.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c index dee1d15ba52c..a593b91ed1d1 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -773,7 +773,8 @@ static const struct io_op_def io_op_defs[] = { .buffer_select = 1, .needs_async_data = 1, .async_size = sizeof(struct io_async_rw), - .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_BLKCG, + .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_BLKCG | + IO_WQ_WORK_FILES, }, [IORING_OP_WRITEV] = { .needs_file = 1, @@ -783,7 +784,7 @@ static const struct io_op_def io_op_defs[] = { .needs_async_data = 1, .async_size = sizeof(struct io_async_rw), .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_BLKCG | - IO_WQ_WORK_FSIZE, + IO_WQ_WORK_FSIZE | IO_WQ_WORK_FILES, }, [IORING_OP_FSYNC] = { .needs_file = 1, @@ -794,7 +795,8 @@ static const struct io_op_def io_op_defs[] = { .unbound_nonreg_file = 1, .pollin = 1, .async_size = sizeof(struct io_async_rw), - .work_flags = IO_WQ_WORK_BLKCG | IO_WQ_WORK_MM, + .work_flags = IO_WQ_WORK_BLKCG | IO_WQ_WORK_MM | + IO_WQ_WORK_FILES, }, [IORING_OP_WRITE_FIXED] = { .needs_file = 1, @@ -803,7 +805,7 @@ static const struct io_op_def io_op_defs[] = { .pollout = 1, .async_size = sizeof(struct io_async_rw), .work_flags = IO_WQ_WORK_BLKCG | IO_WQ_WORK_FSIZE | - IO_WQ_WORK_MM, + IO_WQ_WORK_MM | IO_WQ_WORK_FILES, }, [IORING_OP_POLL_ADD] = { .needs_file = 1, @@ -857,7 +859,7 @@ static const struct io_op_def io_op_defs[] = { .pollout = 1, .needs_async_data = 1, .async_size = sizeof(struct io_async_connect), - .work_flags = IO_WQ_WORK_MM, + .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_FS, }, [IORING_OP_FALLOCATE] = { .needs_file = 1, @@ -885,7 +887,8 @@ static const struct io_op_def io_op_defs[] = { .pollin = 1, .buffer_select = 1, .async_size = sizeof(struct io_async_rw), - .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_BLKCG, + .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_BLKCG | + IO_WQ_WORK_FILES, }, [IORING_OP_WRITE] = { .needs_file = 1, @@ -894,7 +897,7 @@ static const struct io_op_def io_op_defs[] = { .pollout = 1, .async_size = sizeof(struct io_async_rw), .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_BLKCG | - IO_WQ_WORK_FSIZE, + IO_WQ_WORK_FSIZE | IO_WQ_WORK_FILES, }, [IORING_OP_FADVISE] = { .needs_file = 1, @@ -907,14 +910,16 @@ static const struct io_op_def io_op_defs[] = { .needs_file = 1, .unbound_nonreg_file = 1, .pollout = 1, - .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_BLKCG, + .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_BLKCG | + IO_WQ_WORK_FS, }, [IORING_OP_RECV] = { .needs_file = 1, .unbound_nonreg_file = 1, .pollin = 1, .buffer_select = 1, - .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_BLKCG, + .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_BLKCG | + IO_WQ_WORK_FS, }, [IORING_OP_OPENAT2] = { .work_flags = IO_WQ_WORK_FILES | IO_WQ_WORK_FS |
From: Jens Axboe axboe@kernel.dk
stable inclusion from stable-v5.10.126 commit fb2fbb3c10d779c0163c9c2c7ca1aeb75ef3f7ca category: bugfix bugzilla: 187376, https://gitee.com/src-openeuler/kernel/issues/I5IM3T CVE: CVE-2022-2327
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
A previous commit ended up enabling file tracking for iopoll requests, which conflicts with both of them using the same list entry for tracking. Add a separate list entry just for iopoll requests, avoid this issue.
No upstream commit exists for this issue.
Reported-by: Greg Thelen gthelen@google.com Fixes: df3f3bb5059d ("io_uring: add missing item types for various requests") Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Reviewed-by: Xiu Jianfeng xiujianfeng@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- fs/io_uring.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c index a593b91ed1d1..040d1aafc968 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -696,6 +696,8 @@ struct io_kiocb { */ struct list_head inflight_entry;
+ struct list_head iopoll_entry; + struct percpu_ref *fixed_file_refs; struct callback_head task_work; /* for polled requests, i.e. IORING_OP_POLL_ADD and async armed poll */ @@ -2395,8 +2397,8 @@ static void io_iopoll_queue(struct list_head *again) struct io_kiocb *req;
do { - req = list_first_entry(again, struct io_kiocb, inflight_entry); - list_del(&req->inflight_entry); + req = list_first_entry(again, struct io_kiocb, iopoll_entry); + list_del(&req->iopoll_entry); __io_complete_rw(req, -EAGAIN, 0, NULL); } while (!list_empty(again)); } @@ -2418,14 +2420,14 @@ static void io_iopoll_complete(struct io_ring_ctx *ctx, unsigned int *nr_events, while (!list_empty(done)) { int cflags = 0;
- req = list_first_entry(done, struct io_kiocb, inflight_entry); + req = list_first_entry(done, struct io_kiocb, iopoll_entry); if (READ_ONCE(req->result) == -EAGAIN) { req->result = 0; req->iopoll_completed = 0; - list_move_tail(&req->inflight_entry, &again); + list_move_tail(&req->iopoll_entry, &again); continue; } - list_del(&req->inflight_entry); + list_del(&req->iopoll_entry);
if (req->flags & REQ_F_BUFFER_SELECTED) cflags = io_put_rw_kbuf(req); @@ -2461,7 +2463,7 @@ static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events, spin = !ctx->poll_multi_file && *nr_events < min;
ret = 0; - list_for_each_entry_safe(req, tmp, &ctx->iopoll_list, inflight_entry) { + list_for_each_entry_safe(req, tmp, &ctx->iopoll_list, iopoll_entry) { struct kiocb *kiocb = &req->rw.kiocb;
/* @@ -2470,7 +2472,7 @@ static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events, * and complete those lists first, if we have entries there. */ if (READ_ONCE(req->iopoll_completed)) { - list_move_tail(&req->inflight_entry, &done); + list_move_tail(&req->iopoll_entry, &done); continue; } if (!list_empty(&done)) @@ -2482,7 +2484,7 @@ static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events,
/* iopoll may have completed current req */ if (READ_ONCE(req->iopoll_completed)) - list_move_tail(&req->inflight_entry, &done); + list_move_tail(&req->iopoll_entry, &done);
if (ret && spin) spin = false; @@ -2715,7 +2717,7 @@ static void io_iopoll_req_issued(struct io_kiocb *req) struct io_kiocb *list_req;
list_req = list_first_entry(&ctx->iopoll_list, struct io_kiocb, - inflight_entry); + iopoll_entry); if (list_req->file != req->file) ctx->poll_multi_file = true; } @@ -2725,9 +2727,9 @@ static void io_iopoll_req_issued(struct io_kiocb *req) * it to the front so we find it first. */ if (READ_ONCE(req->iopoll_completed)) - list_add(&req->inflight_entry, &ctx->iopoll_list); + list_add(&req->iopoll_entry, &ctx->iopoll_list); else - list_add_tail(&req->inflight_entry, &ctx->iopoll_list); + list_add_tail(&req->iopoll_entry, &ctx->iopoll_list);
if ((ctx->flags & IORING_SETUP_SQPOLL) && wq_has_sleeper(&ctx->sq_data->wait))
From: Florian Westphal fw@strlen.de
stable inclusion from stable-v5.10.135 commit 440dccd80f627e0e11ceb0429e4cdab61857d17e category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I5J9R4?from=project-issue CVE: CVE-2022-36946
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
[ Upstream commit 99a63d36cb3ed5ca3aa6fcb64cffbeaf3b0fb164 ]
Domingo Dirutigliano and Nicola Guerrera report kernel panic when sending nf_queue verdict with 1-byte nfta_payload attribute.
The IP/IPv6 stack pulls the IP(v6) header from the packet after the input hook.
If user truncates the packet below the header size, this skb_pull() will result in a malformed skb (skb->len < 0).
Fixes: 7af4cc3fa158 ("[NETFILTER]: Add "nfnetlink_queue" netfilter queue handler over nfnetlink") Reported-by: Domingo Dirutigliano pwnzer0tt1@proton.me Signed-off-by: Florian Westphal fw@strlen.de Reviewed-by: Pablo Neira Ayuso pablo@netfilter.org Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Ziyang Xuan william.xuanziyang@huawei.com Reviewed-by: Yue Haibing yuehaibing@huawei.com Reviewed-by: Xiu Jianfeng xiujianfeng@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- net/netfilter/nfnetlink_queue.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 1640da5c5077..72d30922ed29 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -838,11 +838,16 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) }
static int -nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e, int diff) +nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int diff) { struct sk_buff *nskb;
if (diff < 0) { + unsigned int min_len = skb_transport_offset(e->skb); + + if (data_len < min_len) + return -EINVAL; + if (pskb_trim(e->skb, data_len)) return -ENOMEM; } else if (diff > 0) {