sched/fair: NULL deref in pick_next_task_fair (v4.19) -- tasks_timeline empty, nr_running == -1 (two production dumps)

Qiurong Fang <[email protected]>
Newsgroups org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Hello,

We have encountered the same crash signature in two unrelated production
environments, each with a kdump-captured vmcore. Both crashes occurred
after long uptime (738 days / 290 days) and dereferenced NULL in
pick_next_task_fair(). The root cfs_rq state on the crashing CPU is
identical in both cases.


=== 1. Environment ===

Site A:
  - aarch64, HiSilicon Kunpeng 920 (HIP08), 96 CPUs(NUMA: 4 nodes, 24 CPUs/node), 382 GB
  - Kernel 4.19.90-23.43.v2101 (vendor distro kernel based on 4.19), GCC 7.3
  - Uptime 738 days;

Site B:
  - aarch64, HiSilicon Kunpeng 920 (HIP08), 128 CPUs(NUMA: 4 nodes, 32 CPUs/node), 1 TB
  - Kernel 4.19.90-89.17.v2401 (newer vendor build), GCC 7.3
  - Uptime 290 days


=== 2. Crash site ===

In both cases the NULL comes from the same place: the non-zero count
prevents the idle path, so pick_next_entity() takes rb_leftmost from
an empty tree and gets NULL.

  again:
      if (!cfs_rq->nr_running)    /* 0xFFFFFFFF != 0, no idle */
          goto idle;

--- Site A dmesg ---

[63777450.752746] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000160
[63777450.753146] Mem abort info:
[63777450.753299]   ESR = 0x96000005
...
[63777450.755251] Internal error: Oops: 96000005 [#1] SMP
[63777450.755489] Modules linked in: iptable_filter udp_diag raw_diag unix_diag af_packet_diag netlink_diag tcp_diag inet_diag bonding vfat fat ipmi_ssif aes_ce_blk crypto_simd cryptd aes_ce_cipher crct10dif_ce ghash_ce sha2_ce sha256_arm64 sha1_ce hns_roce_hw_v2 hns_roce ib_uverbs ses sbsa_gwdt ib_core enclosure ofpart cmdlinepart ipmi_si ipmi_devintf hi_sfc ipmi_msghandler mtd spi_dw_mmio sch_fq_codel binfmt_misc ip_tables realtek hinic hns3 hclge megaraid_sas hisi_sas_v3_hw hnae3 hisi_sas_main host_edma_drv
[63777450.757458] Process ksoftirqd/65 (pid: 339, stack limit = 0x000000001f6f62e2)
[63777450.764478] CPU: 65 PID: 339 Comm: ksoftirqd/65 Kdump: loaded Not tainted 4.19.90-23.43.v2101.ky10.aarch64 #1
[63777450.778683] Hardware name: Huawei TaiShan 200 (Model 2280)/BC82AMDDA, BIOS 1.38 07/04/2020
[63777450.793264] pstate: 60c00089 (nZCv daIf +PAN +UAO)
[63777450.800561] pc : pick_next_task_fair+0x88/0x640
[63777450.807710] lr : pick_next_task_fair+0x88/0x640
[63777450.814599] sp : ffffa037c3d7bd10
[63777450.821394] x29: ffffa037c3d7bd10 x28: ffff000048c5e248
...
[63777450.911587] x1 : 0000000000000000 x0 : 0000000000000000
[63777450.917053] Call trace:
[63777450.922275]  pick_next_task_fair+0x88/0x640
[63777450.927392]  __schedule+0x71c/0x958
[63777450.932458]  schedule+0x2c/0x88
[63777450.937190]  smpboot_thread_fn+0x1b4/0x1b8
[63777450.941813]  kthread+0x134/0x138
[63777450.946248]  ret_from_fork+0x10/0x18
[63777450.950520] Code: 54000221 aa1403e0 aa1303e1 97ffcf29 (f940b014)

Corresponding source (4.19 pick_next_task_fair):

      se = pick_next_entity(cfs_rq, curr);   /* returns NULL */
      cfs_rq = group_cfs_rq(se);             /* NULL->my_q, +0x160, crash */

--- Site B dmesg ---

[25097461.360687] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000040
[25097461.370128] Mem abort info:
[25097461.373601]   ESR = 0x96000005
...
[25097461.417991] Internal error: Oops: 96000005 [#1] SMP
[25097461.423539] Modules linked in: nfsd nfs_acl binfmt_misc rpcsec_gss_krb5 auth_rpcgss nfsv4 dns_resolver nfs lockd grace fscache bonding sunrpc ipmi_ssif vfat fat aes_ce_blk crypto_simd joydev cryptd aes_ce_cipher crct10dif_ce ofpart ghash_ce cmdlinepart ipmi_si sha1_ce ses sbsa_gwdt ky_lpcmux enclosure hi_sfc ipmi_devintf mtd ipmi_msghandler spi_dw_mmio sch_fq_codel ip_tables sha2_ce nvme hinic sha256_arm64 nvme_core nfit hisi_sas_v3_hw nvme_common ngbe megaraid_sas libnvdimm hisi_sas_main host_edma_drv dm_mirror dm_region_hash dm_log
[25097461.471273] Process T1004_LockWaitM (pid: 4090813, stack limit = 0x0000000096656505)
[25097461.479672] CPU: 92 PID: 4090813 Comm: T1004_LockWaitM Kdump: loaded Not tainted 4.19.90-89.17.v2401.ky10.aarch64 #1
[25097461.497852] Hardware name: PowerLeader PR210K/BC82AMDYA, BIOS 6.57 05/17/2023
[25097461.505644] pstate: 60400089 (nZCv daIf +PAN -UAO)
[25097461.511111] pc : set_next_entity+0x20/0x6f8
[25097461.515968] lr : pick_next_task_fair+0x2e8/0x548
[25097461.521255] sp : ffff8041a56d7c60
[25097461.525245] x29: ffff8041a56d7c60 x28: ffff8040a2593800
...
[25097461.549161] x21: 0000000000000000 x20: 0000000000000000
...
[25097461.608946] x1 : 0000000000000000 x0 : ffff561d3afdf1d8
[25097461.614926] Call trace:
[25097461.618054]  set_next_entity+0x20/0x6f8
[25097461.622563]  pick_next_task_fair+0x2e8/0x548
[25097461.627509]  __schedule+0x6e4/0x840
[25097461.631673]  schedule+0x30/0xe0
[25097461.635493]  do_nanosleep+0x78/0x168
[25097461.639747]  hrtimer_nanosleep+0x88/0x100
[25097461.644429]  sys_nanosleep+0x94/0xb8
[25097461.648680]  el0_svc_naked+0x44/0x48
[25097461.652931] Code: aa0103f4 aa0003f3 aa1e03e0 d503201f (b9404280)

Corresponding source (4.19 pick_next_task_fair, simple label):

      se = pick_next_entity(cfs_rq, NULL);   /* returns NULL */
      set_next_entity(cfs_rq, se);           /* se->on_rq, +0x40, crash */


=== 3. Root cfs_rq / rq state from vmcore ===

field                                          observed value
-------------------------------------------  --------------------
rq->nr_running                                0
rq->load.weight                                2^64 - 1048576
cfs_rq->nr_running                             0xFFFFFFFF (-1)
cfs_rq->h_nr_running                           0xFFFFFFFF (-1)
cfs_rq->load.weight                            0
tasks_timeline->rb_root.rb_node/rb_leftmost    NULL / NULL
rq->cfs_tasks list length                      0
rq->curr                                       task se (se->on_rq=0)

The two sites use hardware from different vendors and kernel builds
about a year apart. This issue has only been seen on Kunpeng 920 arm64
(kernel 4.19); it has not appeared on x86 (kernel 4.19). The corruption
affects three fields (cfs.nr -1, cfs.h_nr -1, rq.load -1048576, the
latter being exactly one nice-0 task weight NICE_0_LOAD).

--- Site A (cpu 65) ---

struct rq (cpu 65):
  .nr_running = (unsigned int)0
  .load.weight = (unsigned long)18446744073708503040
  .nr_switches = (u64)113264737287
  ...
  .curr->pid = (pid_t)339
  .curr->on_rq = (int)0
  .cfs_tasks len = 0

struct cfs_rq (root, cpu 65):
(struct cfs_rq){
	.load = (struct load_weight){
		.weight = (unsigned long)0,
		.inv_weight = (u32)0,
	},
	.runnable_weight = (unsigned long)0,
	.nr_running = (unsigned int)4294967295,
	.h_nr_running = (unsigned int)4294967295,
	.exec_clock = (u64)0,
	.min_vruntime = (u64)12868847681674577,
	.tasks_timeline = (struct rb_root_cached){
		.rb_root = (struct rb_root){
			.rb_node = (struct rb_node *)0x0,
		},
		.rb_leftmost = (struct rb_node *)0x0,
	},
	.curr = (struct sched_entity *)0xffffa037c3d83ec0,
	.next = (struct sched_entity *)0x0,
	.last = (struct sched_entity *)0x0,
	.skip = (struct sched_entity *)0x0,
	...
	.tg = (struct task_group *)root_task_group+0x0 = 0xffff000049a364c0,
	.runtime_enabled = (int)0,
	.throttled = (int)0,
	.throttle_count = (int)0,
	...
}

--- Site B (cpu 92) ---

struct rq (cpu 92):
  .nr_running = (unsigned int)0
  .load.weight = (unsigned long)18446744073708503040
  .nr_switches = (u64)77284029461
  ...
  .curr->pid = (pid_t)4090813
  .curr->on_rq = (int)0
  .cfs_tasks len = 0

struct cfs_rq (root, cpu 92):
(struct cfs_rq){
	.load = (struct load_weight){
		.weight = (unsigned long)0,
		.inv_weight = (u32)0,
	},
	.runnable_weight = (unsigned long)0,
	.nr_running = (unsigned int)4294967295,
	.h_nr_running = (unsigned int)4294967295,
	.exec_clock = (u64)0,
	.min_vruntime = (u64)1181660162701980,
	.tasks_timeline = (struct rb_root_cached){
		.rb_root = (struct rb_root){
			.rb_node = (struct rb_node *)0x0,
		},
		.rb_leftmost = (struct rb_node *)0x0,
	},
	.curr = (struct sched_entity *)0x0,
	.next = (struct sched_entity *)0x0,
	.last = (struct sched_entity *)0x0,
	.skip = (struct sched_entity *)0x0,
	...
	.tg = (struct task_group *)root_task_group+0x0 = 0xffff561d3d1b6100,
	.runtime_enabled = (int)0,
	.throttled = (int)0,
	.throttle_count = (int)0,
	.idle_h_nr_running = (unsigned int)0,
	...
}


=== 4. Code analysis ===

Verified against the kernel source tag: the sole writers of root
cfs_rq.nr_running, root cfs_rq.load and rq.load in the entire scheduler
are the following two functions. Both are called under rq->lock, so no
race condition is expected:

  account_entity_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
  {
  	update_load_add(&cfs_rq->load, se->load.weight);
  	if (!parent_entity(se))
  		update_load_add(&rq_of(cfs_rq)->load, se->load.weight);
  	... /* cfs_tasks list, numa accounting, irrelevant here */
  	cfs_rq->nr_running++;
  }

  account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
  {
  	update_load_sub(&cfs_rq->load, se->load.weight);
  	if (!parent_entity(se))
  		update_load_sub(&rq_of(cfs_rq)->load, se->load.weight);
  	...
  	cfs_rq->nr_running--;
  }

For the three fields visible on a given rq, each accounting call has one
of three effects, and (-1, 0, -w) is not in the reachable set:

  (a) root-level entity enqueue:  (cfs.nr +1, cfs.load +w, rq.load +w)
  (b) root-level entity dequeue:  (cfs.nr -1, cfs.load -w, rq.load -w)
  (c) non-root-level entity:       (0, 0, 0)

From source inspection, the sole writers of nr_running and load are
account_entity_enqueue / account_entity_dequeue,both called under
rq->lock protection, which makes the observed field state hard to
explain.

Has anyone seen a similar issue on arm64? Any debugging suggestions
would be appreciated.

The full panic dmesg for both crashes is posted above. Both crashes have
kdump-captured vmcores; any data from them (struct fields, disassembly,
etc.) can be queried on request and reported back.

--
Thanks
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.