Go: tiempo de ejecución: mlock de la pila de señales falló: 12

Creado en 25 feb. 2020  ·  128Comentarios  ·  Fuente: golang/go

¿Qué versión de Go estás usando ( go version )?

 $ go versión
 go versión go1.14rc1 linux / amd64

¿Este problema se reproduce con la última versión?

Golpeé esto con la imagen de la ventana acoplable golang:1.14-rc-alpine , el error no ocurre en 1.13.

¿Qué sistema operativo y arquitectura de procesador está utilizando ( go env )?

go env Salida

$ ir env
GO111MODULE = ""
GOARCH = "amd64"
GOBIN = ""
GOCACHE = "/ root / .cache / go-build"
GOENV = "/ root / .config / go / env"
GOEXE = ""
GOFLAGS = ""
GOHOSTARCH = "amd64"
GOHOSTOS = "linux"
GOINSECURE = ""
GONOPROXY = ""
GONOSUMDB = ""
GOOS = "linux"
GOPATH = "/ ir"
GOPRIVATE = ""
GOPROXY = "https: //proxy.golang.org,direct"
GOROOT = "/ usr / local / go"
GOSUMDB = "sum.golang.org"
GOTMPDIR = ""
GOTOOLDIR = "/ usr / local / go / pkg / tool / linux_amd64"
GCCGO = "gccgo"
AR = "ar"
CC = "gcc"
CXX = "g ++"
CGO_ENABLED = "1"
GOMOD = ""
CGO_CFLAGS = "- g -O2"
CGO_CPPFLAGS = ""
CGO_CXXFLAGS = "- g -O2"
CGO_FFLAGS = "- g -O2"
CGO_LDFLAGS = "- g -O2"
PKG_CONFIG = "pkg-config"
GOGCCFLAGS = "- fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-argumentos -fmessage-length = 0 -fdebug-prefix-map = / tmp / go-build968395959 = / tmp / go-build -gno-record- interruptores-gcc "

¿Qué hiciste?

Clone https://github.com/ethereum/go-ethereum , reemplace la versión del constructor en Dockerfile por golang:1.14-rc-alpine (o use el Dockerfile de abajo) , luego desde la raíz construya la imagen de

$ docker build .

FROM golang:1.14-rc-alpine

RUN apk add --no-cache make gcc musl-dev linux-headers git

ADD . /go-ethereum
RUN cd /go-ethereum && make geth

¿Qué esperabas ver?

Go debería ejecutar nuestros scripts de compilación con éxito.

¿Qué viste en su lugar?

Step 4/9 : RUN cd /go-ethereum && make geth
 ---> Running in 67781151653c
env GO111MODULE=on go run build/ci.go install ./cmd/geth
runtime: mlock of signal stack failed: 12
runtime: increase the mlock limit (ulimit -l) or
runtime: update your kernel to 5.3.15+, 5.4.2+, or 5.5+
fatal error: mlock failed

runtime stack:
runtime.throw(0xa3b461, 0xc)
    /usr/local/go/src/runtime/panic.go:1112 +0x72
runtime.mlockGsignal(0xc0004a8a80)
    /usr/local/go/src/runtime/os_linux_x86.go:72 +0x107
runtime.mpreinit(0xc000401880)
    /usr/local/go/src/runtime/os_linux.go:341 +0x78
runtime.mcommoninit(0xc000401880)
    /usr/local/go/src/runtime/proc.go:630 +0x108
runtime.allocm(0xc000033800, 0xa82400, 0x0)
    /usr/local/go/src/runtime/proc.go:1390 +0x14e
runtime.newm(0xa82400, 0xc000033800)
    /usr/local/go/src/runtime/proc.go:1704 +0x39
runtime.startm(0x0, 0xc000402901)
    /usr/local/go/src/runtime/proc.go:1869 +0x12a
runtime.wakep(...)
    /usr/local/go/src/runtime/proc.go:1953
runtime.resetspinning()
    /usr/local/go/src/runtime/proc.go:2415 +0x93
runtime.schedule()
    /usr/local/go/src/runtime/proc.go:2527 +0x2de
runtime.mstart1()
    /usr/local/go/src/runtime/proc.go:1104 +0x8e
runtime.mstart()
    /usr/local/go/src/runtime/proc.go:1062 +0x6e

...
make: *** [Makefile:16: geth] Error 2
NeedsInvestigation

Comentario más útil

El error del kernel se manifestó como una corrupción de memoria aleatoria en Go 1.13 (con y sin programación preventiva). Lo nuevo en Go 1.14 es que detectamos la presencia del error, intentamos solucionarlo y preferimos fallar temprano y en voz alta si eso no es posible. Puede ver los detalles en el número al que lo referí.

Ya que me ha llamado deshonesto y desagradable, le recordaré nuevamente sobre el código de conducta: https://golang.org/conduct. También he terminado de participar en esta conversación.

Todos 128 comentarios

Esa es la consecuencia de intentar solucionar un error del kernel que afecta significativamente a los programas Go. Consulte https://github.com/golang/go/issues/35777. El mensaje de error sugiere las dos únicas correcciones disponibles conocidas: aumentar el ulimit o actualizar a un kernel más nuevo.

El mensaje de error sugiere las dos únicas correcciones disponibles conocidas: aumentar el ulimit o actualizar a un kernel más nuevo.

Bueno, estoy ejecutando la imagen oficial de la ventana acoplable alpina, cuyo propósito es poder crear un programa Go. Aparentemente no puede. En mi humilde opinión, la imagen ascendente debería ser la que se corrigió para cumplir su propósito, no nuestra infraestructura de compilación para solucionar un error en la imagen ascendente.

¿La imagen de Alpine la mantiene el equipo de Go? (Pregunta genuina. No lo sé.) De cualquier manera, sí, la imagen debería arreglarse, idealmente con una actualización del kernel.

No estoy completamente seguro de quién y cómo mantiene las imágenes de la ventana acoplable (https://hub.docker.com/_/golang), pero el repositorio de la ventana acoplable es una "Imagen oficial", que es un estado muy difícil de obtener. así que asumo que alguien lo suficientemente alto en la cadena alimentaria es responsable.

Es "mantenido por la comunidad de Docker". Los problemas deben archivarse en

https://github.com/docker-library/golang/issues

EDITAR: el problema es el kernel del host, no la imagen de la biblioteca de Docker, por lo que no pueden solucionarlo.

Entonces, ¿la solución oficial para Go crashing es señalar con el dedo a todos los demás para piratear tu código? Tiene sentido.

@karalabe Me gustaría recordarte https://golang.org/conduct. En particular, sea respetuoso y caritativo.

Por favor conteste la pregunta

Es una práctica estándar redirigir los problemas al sistema de seguimiento de problemas correcto.

Hay una discusión extensa de posibles soluciones y correcciones en el problema al que me vinculé anteriormente, si desea ver qué opciones se consideraron en el lado Go.

Este problema no ocurre con Go 1.13. Ergo, es un error introducido en Go 1.14.

Decir que no puede arreglarlo y decirle a la gente que use soluciones es deshonesto, porque revertir un fragmento de código en realidad lo arreglaría. Una solución alternativa sería detectar las plataformas / núcleos problemáticos y proporcionar un mecanismo de respaldo integrado en Go.

Decirle a la gente que use un kernel diferente es especialmente desagradable, porque no es como si la mayoría de la gente pudiera construir un nuevo kernel. Si alpine no lanza un nuevo kernel, no hay mucho que la mayoría de los desarrolladores puedan hacer. Y, por último, si su proyecto se basa en una infraestructura estable en la que no puede simplemente intercambiar núcleos, nuevamente está en un aprieto.

Es una práctica estándar redirigir los problemas al sistema de seguimiento de problemas correcto.

El hecho de que Go falle no es culpa de Docker. Redirigir un bloqueo de Go a un repositorio de Docker es una desviación.

También puede deshabilitar la programación preventiva en tiempo de ejecución

$ GODEBUG=asyncpreemptoff=1 ./your_app

@ianlancetaylor tenemos una sugerencia para hacer esto cuando se ejecuta en un kernel afectado; es eso viable?

Por cierto, es un problema conocido que los módulos de la biblioteca de Docker no reciben actualizaciones oportunas, lo cual es un problema de seguridad. Caveat emptor.

El error del kernel se manifestó como una corrupción de memoria aleatoria en Go 1.13 (con y sin programación preventiva). Lo nuevo en Go 1.14 es que detectamos la presencia del error, intentamos solucionarlo y preferimos fallar temprano y en voz alta si eso no es posible. Puede ver los detalles en el número al que lo referí.

Ya que me ha llamado deshonesto y desagradable, le recordaré nuevamente sobre el código de conducta: https://golang.org/conduct. También he terminado de participar en esta conversación.

@karalabe , me equivoqué, el problema es el kernel de su host, no la imagen de Docker. ¿No puede actualizarlo?

Estoy en la última versión de Ubuntu y en el último kernel disponible. Aparentemente, todos los núcleos de Ubuntu disponibles no son adecuados para Go 1.14 https://packages.ubuntu.com/search?keywords=linux-image-generic según el mensaje de error.

¿Puede agregar la salida de $ uname -a al texto del problema principal? ¿Y tal vez eliminar los rastros de pila de goroutine?

Publiqué una nota en golang-dev.

cc @aclements

Cuando dice que está en el último ubuntu y kernel, ¿qué quiere decir exactamente (es decir, salida de dpkg -l linux-image- *, lsb_release -a, uname -a, ese tipo de cosas) porque, por lo que puedo ver, La corrección está en el kernel en el bolsillo de actualizaciones tanto para 19.10 (versión estable actual) como para 20.04 (versión de desarrollo). No está en el kernel de GA para 18.04, pero sí en el kernel de HWE, pero entre otros, no están construidos con gcc 9 y, por lo tanto, no deberían verse afectados de todos modos.

@networkimprov La desactivación de la preferencia de señal hace que sea menos probable que ocurra el error, pero aún está presente. Es un error en ciertas versiones del kernel de Linux. El error afecta a todos los programas en todos los idiomas. Es particularmente probable que sea observable con los programas Go que usan la preferencia de señal, pero también está presente para todos los demás programas.

Go intenta solucionar el error bloqueando la pila de señales. Eso funciona bien a menos que se encuentre con el límite de mlock. Supongo que una desventaja de esta solución es que hacemos que el problema sea muy visible, en lugar de fallar ocasionalmente debido a la corrupción aleatoria de la memoria, como sucedería si no hiciéramos el mlock.

En algún momento, no hay forma de evitar un error del kernel.

@karalabe

Estoy en el último Ubuntu y el último kernel disponible

$ docker pull -q ubuntu:latest
docker.io/library/ubuntu:latest
$ docker run --rm -i -t ubuntu
root<strong i="9">@e2689d364a25</strong>:/# uname -a
Linux e2689d364a25 5.4.8-050408-generic #202001041436 SMP Sat Jan 4 19:40:55 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

que satisface los requisitos mínimos de versión.

Similar:

$ docker pull -q golang:1.14-alpine
docker.io/library/golang:1.14-alpine
$ docker run --rm -i -t golang:1.14-alpine
/go # uname -a
Linux d4a35392c5b8 5.4.8-050408-generic #202001041436 SMP Sat Jan 4 19:40:55 UTC 2020 x86_64 Linux

¿Puedes aclarar lo que estás viendo?

@mwhudson

$ dpkg -l linux-image-*
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                                   Version      Architecture Description
+++-======================================-============-============-===============================================================
rc  linux-image-4.13.0-16-generic          4.13.0-16.19 amd64        Linux kernel image for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-4.13.0-19-generic          4.13.0-19.22 amd64        Linux kernel image for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-4.13.0-21-generic          4.13.0-21.24 amd64        Linux kernel image for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-4.13.0-25-generic          4.13.0-25.29 amd64        Linux kernel image for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-4.13.0-36-generic          4.13.0-36.40 amd64        Linux kernel image for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-4.13.0-37-generic          4.13.0-37.42 amd64        Linux kernel image for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-4.13.0-38-generic          4.13.0-38.43 amd64        Linux kernel image for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-4.13.0-41-generic          4.13.0-41.46 amd64        Linux kernel image for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-4.13.0-45-generic          4.13.0-45.50 amd64        Linux kernel image for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-4.15.0-23-generic          4.15.0-23.25 amd64        Signed kernel image generic
rc  linux-image-4.15.0-30-generic          4.15.0-30.32 amd64        Signed kernel image generic
rc  linux-image-4.15.0-32-generic          4.15.0-32.35 amd64        Signed kernel image generic
rc  linux-image-4.15.0-34-generic          4.15.0-34.37 amd64        Signed kernel image generic
rc  linux-image-4.15.0-36-generic          4.15.0-36.39 amd64        Signed kernel image generic
rc  linux-image-4.15.0-39-generic          4.15.0-39.42 amd64        Signed kernel image generic
rc  linux-image-4.15.0-42-generic          4.15.0-42.45 amd64        Signed kernel image generic
rc  linux-image-4.15.0-43-generic          4.15.0-43.46 amd64        Signed kernel image generic
rc  linux-image-4.15.0-45-generic          4.15.0-45.48 amd64        Signed kernel image generic
rc  linux-image-4.15.0-47-generic          4.15.0-47.50 amd64        Signed kernel image generic
rc  linux-image-4.18.0-17-generic          4.18.0-17.18 amd64        Signed kernel image generic
rc  linux-image-5.0.0-13-generic           5.0.0-13.14  amd64        Signed kernel image generic
rc  linux-image-5.0.0-15-generic           5.0.0-15.16  amd64        Signed kernel image generic
rc  linux-image-5.0.0-16-generic           5.0.0-16.17  amd64        Signed kernel image generic
rc  linux-image-5.0.0-17-generic           5.0.0-17.18  amd64        Signed kernel image generic
rc  linux-image-5.0.0-19-generic           5.0.0-19.20  amd64        Signed kernel image generic
rc  linux-image-5.0.0-20-generic           5.0.0-20.21  amd64        Signed kernel image generic
rc  linux-image-5.0.0-21-generic           5.0.0-21.22  amd64        Signed kernel image generic
rc  linux-image-5.0.0-25-generic           5.0.0-25.26  amd64        Signed kernel image generic
rc  linux-image-5.0.0-27-generic           5.0.0-27.28  amd64        Signed kernel image generic
rc  linux-image-5.0.0-29-generic           5.0.0-29.31  amd64        Signed kernel image generic
rc  linux-image-5.0.0-32-generic           5.0.0-32.34  amd64        Signed kernel image generic
rc  linux-image-5.3.0-19-generic           5.3.0-19.20  amd64        Signed kernel image generic
rc  linux-image-5.3.0-22-generic           5.3.0-22.24  amd64        Signed kernel image generic
rc  linux-image-5.3.0-23-generic           5.3.0-23.25  amd64        Signed kernel image generic
rc  linux-image-5.3.0-24-generic           5.3.0-24.26  amd64        Signed kernel image generic
rc  linux-image-5.3.0-26-generic           5.3.0-26.28  amd64        Signed kernel image generic
ii  linux-image-5.3.0-29-generic           5.3.0-29.31  amd64        Signed kernel image generic
ii  linux-image-5.3.0-40-generic           5.3.0-40.32  amd64        Signed kernel image generic
rc  linux-image-extra-4.13.0-16-generic    4.13.0-16.19 amd64        Linux kernel extra modules for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-extra-4.13.0-19-generic    4.13.0-19.22 amd64        Linux kernel extra modules for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-extra-4.13.0-21-generic    4.13.0-21.24 amd64        Linux kernel extra modules for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-extra-4.13.0-25-generic    4.13.0-25.29 amd64        Linux kernel extra modules for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-extra-4.13.0-36-generic    4.13.0-36.40 amd64        Linux kernel extra modules for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-extra-4.13.0-37-generic    4.13.0-37.42 amd64        Linux kernel extra modules for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-extra-4.13.0-38-generic    4.13.0-38.43 amd64        Linux kernel extra modules for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-extra-4.13.0-41-generic    4.13.0-41.46 amd64        Linux kernel extra modules for version 4.13.0 on 64 bit x86 SMP
rc  linux-image-extra-4.13.0-45-generic    4.13.0-45.50 amd64        Linux kernel extra modules for version 4.13.0 on 64 bit x86 SMP
ii  linux-image-generic                    5.3.0.40.34  amd64        Generic Linux kernel image

$ lsb_release -a

No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 19.10
Release:    19.10
Codename:   eoan
$ uname -a

Linux roaming-parsley 5.3.0-40-generic #32-Ubuntu SMP Fri Jan 31 20:24:34 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$ sudo apt-get dist-upgrade 

Reading package lists... Done
Building dependency tree       
Reading state information... Done
Calculating upgrade... Done
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

@myitcv

FROM golang:1.14-alpine
RUN  apk add --no-cache make gcc musl-dev linux-headers git wget

RUN \
  wget -O geth.tgz "https://github.com/ethereum/go-ethereum/archive/v1.9.11.tar.gz" && \
  mkdir /go-ethereum && tar -C /go-ethereum -xzf geth.tgz --strip-components=1 && \
  cd /go-ethereum && make geth
$ docker build .

Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM golang:1.14-alpine
1.14-alpine: Pulling from library/golang
c9b1b535fdd9: Already exists 
cbb0d8da1b30: Already exists 
d909eff28200: Already exists 
8b9d9d6824f5: Pull complete 
a50ef8b76e53: Pull complete 
Digest: sha256:544b5e7984e7b2e7a2a9b967bbab6264cf91a3b3816600379f5dc6fbc09466cc
Status: Downloaded newer image for golang:1.14-alpine
 ---> 51e47ee4db58

Step 2/3 : RUN  apk add --no-cache make gcc musl-dev linux-headers git wget
 ---> Running in 879f98ddb4ff
[...]
OK: 135 MiB in 34 packages
Removing intermediate container 879f98ddb4ff
 ---> 9132e4dae4c3

Step 3/3 : RUN   wget -O geth.tgz "https://github.com/ethereum/go-ethereum/archive/v1.9.11.tar.gz" &&   mkdir /go-ethereum && tar -C /go-ethereum -xzf geth.tgz --strip-components=1 &&   cd /go-ethereum && make geth
 ---> Running in a24c806c60d3
2020-02-26 07:18:54--  https://github.com/ethereum/go-ethereum/archive/v1.9.11.tar.gz
[...]
2020-02-26 07:18:58 (2.48 MB/s) - 'geth.tgz' saved [8698235]

env GO111MODULE=on go run build/ci.go install ./cmd/geth
runtime: mlock of signal stack failed: 12
runtime: increase the mlock limit (ulimit -l) or
runtime: update your kernel to 5.3.15+, 5.4.2+, or 5.5+
fatal error: mlock failed

Lo siento, mi comentario anterior fue engañoso. Porque, por supuesto, la versión del kernel devuelta por uname -a dentro del contenedor Docker será la del host.

Por lo tanto, por:

$ uname -a

Linux roaming-parsley 5.3.0-40-generic #32-Ubuntu SMP Fri Jan 31 20:24:34 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

necesita actualizar el kernel del sistema operativo host.

FWIW, los pasos que estableciste anteriormente usando Alpine para make geth funcionan para mí .:

...
Done building.
Run "./build/bin/geth" to launch geth.

Sí, pero en mis publicaciones anteriores resalté que ya estoy en la última versión de Ubuntu y he instalado el último kernel disponible desde el repositorio de paquetes. No veo cómo podría actualizar mi kernel para que funcione con Go 1.14, aparte de reconstruir todo el kernel desde la fuente. ¿Quizás me estoy perdiendo algo?

Solo para enfatizar, entiendo cuál es la solución alternativa y si quiero que funcione, puedo. Abrí este informe de problemas porque esperaba que otras personas eventualmente encontraran el mismo problema. Si con solo actualizar mi sistema se solucionara el problema, lo aceptaría con gusto como una solución, pero a menos que me falte algo, el kernel fijo no está disponible para los usuarios (recientes) de Ubuntu, por lo que una base de usuarios bastante grande podría verse afectada.

Sí, pero en mis publicaciones anteriores resalté que ya estoy en la última versión de Ubuntu y he instalado el último kernel disponible desde el repositorio de paquetes. No veo cómo podría actualizar mi kernel para que funcione con Go 1.14, aparte de reconstruir todo el kernel desde la fuente. ¿Quizás me estoy perdiendo algo?

Hm sí, acabo de reproducir en focal también. La solución está presente en el git para el kernel de Ubuntu eoan: https://kernel.ubuntu.com/git/ubuntu/ubuntu-eoan.git/commit/?id=59e7e6398a9d6d91cd01bc364f9491dc1bf2a426 y esa confirmación está en la ascendencia de 5.3. 0-40.32, por lo que la solución debería estar en el kernel que está utilizando. En otras palabras, creo que debemos involucrar al equipo del kernel; intentaré hacerlo.

@karalabe - Me acabo de dar cuenta de mi error: pensé que estaba usando la última versión de Ubuntu, de hecho estoy usando eoan .

@mwhudson : solo una cosa a tener en cuenta (aunque probablemente ya sea consciente de esto), un vistazo superficial al código responsable de este cambio:

https://github.com/golang/go/blob/20a838ab94178c55bc4dc23ddc332fce8545a493/src/runtime/os_linux_x86.go#L56 -L61

parece sugerir que el lado Go está comprobando la versión de parche 15 o superior. ¿Qué informa 5.3.0-40.32 como versión de parche? ¿Estoy adivinando 0?

Reabriendo esta discusión hasta que redondeemos el tema aquí.

Un pequeño resumen porque tuve que armarlo yo mismo:

Entonces, parece que el kernel de Ubuntu está parcheado, pero la solución se habilita de todos modos.

Entonces, parece que el kernel de Ubuntu está parcheado, pero la solución se habilita de todos modos.

Oh, claro, sí, debería leer el fallo, ¿no? Esta es la solución que falla en lugar del error original, en un caso en el que la solución no es realmente necesaria, pero no hay una buena manera de que Go sepa esto. Puedo parchear la verificación del paquete Go 1.14 en Ubuntu, pero eso no ayuda a los usuarios que ejecutan, por ejemplo, la imagen docker golang: 1.14-alpine . Hrm.

Supongo que la pregunta es cuántos usuarios están usando núcleos "vulnerables" en este momento. No puede haber tantas distribuciones que estén compilando un kernel sin parchear con gcc 9 a estas alturas.

No puede haber tantos ...

¿Últimas palabras famosas? :D

Sin embargo, con toda seriedad, no creo que la gente actualice los núcleos con frecuencia, y muchos sistemas no pueden. Quizás una mejor pregunta sería qué sistemas / distribuciones usan núcleos vulnerables de forma predeterminada y simplemente asumir que habrá mucha gente atrapada en ellos.

Puedo parchear la verificación del paquete Go 1.14 en Ubuntu, pero eso no ayuda a los usuarios que ejecutan, por ejemplo, la imagen docker golang: 1.14-alpine . Hrm.

También extrañaría los usuarios que construyen desde el código fuente. Por ejemplo, Ethereum crea compilaciones de origen para nuestros PPA porque no hay un paquete Go reciente para todas las distribuciones en Launchpad.

¿Es común que Ubuntu (y otras distribuciones?) Utilicen la selección selectiva en lugar de las siguientes versiones de parches del kernel de Linux? En https://packages.ubuntu.com/search?keywords=linux-image-generic todos los núcleos tienen una versión de parche cero.

En lo que respecta a una búsqueda rápida en Google, Ubuntu no lanza nuevos núcleos después de enviar la distribución, sino que simplemente elige correcciones de seguridad (es decir, sin cambios en la versión del parche). La excepción a esto son las versiones LTS (admitidas durante 5 años), que pueden recibir actualizaciones del kernel cada pocos años para admitir hardware nuevo (pero eso también es muy raro). No conozco otras distribuciones.

Con mi conocimiento limitado en este momento, esto parece extraño. Los lanzamientos de parches están destinados a distribuir parches de manera controlada para que las personas (y en este caso el tiempo de ejecución de Go) puedan saber qué parches están incluidos y cuáles no. Sin embargo, así es como es, así que tenemos que vivir con ello.

Preguntas abiertas:

  • ¿A cuántas personas afecta este problema?
  • ¿Es ulimit una solución alternativa viable?
  • ¿Es Ubuntu la única distribución que "ignora" los números de parche del kernel de Linux?
  • Dependiendo de las respuestas a las preguntas anteriores: ¿Sería razonable agregar una detección especial para Ubuntu?

@neelance

¿Es común que Ubuntu (y otras distribuciones?) Utilicen la selección selectiva en lugar de las siguientes versiones de parches del kernel de Linux?

Muchas distribuciones lo hacen, no solo Ubuntu. Debian lo hace, Red Hat Enterprise Linux lo hace y espero que SUSE también lo haga para sus distribuciones empresariales. La selección selectiva es la única forma de corregir errores en absoluto si no puede seguir de manera agresiva las versiones estables ascendentes (y cambiar las versiones estables a medida que desaparece el soporte ascendente). Fedora es una excepción; después de un rato vuelve a la base del kernel ascendente de la última versión estable.

También está la cuestión de los núcleos patentados utilizados por los motores de contenedores. Ni siquiera podemos buscarlos en las fuentes, y algunos de ellos han mentido sobre los números de versión del kernel en el pasado. Espero que también utilicen la selección de cerezas.

Por lo general, las comprobaciones de versiones en busca de características (o errores) del kernel son realmente una mala idea. Es peor para Go debido al enlace estático, por lo que es imposible cambiar el tiempo de ejecución debajo de una aplicación para corregir las expectativas del kernel.

¿Es común que Ubuntu (y otras distribuciones?) Utilicen la selección selectiva en lugar de las siguientes versiones de parches del kernel de Linux? En https://packages.ubuntu.com/search?keywords=linux-image-generic todos los núcleos tienen una versión de parche cero.

La cadena de la versión base del kernel no cambia, eso es cierto. Pero eso no significa que las versiones estables ascendentes no se fusionen, sino que el número de ABI aumenta cuando hay cambios de código.

Tenga en cuenta que eligió el metapaquete que no muestra el registro de cambios adecuado, aquí puede ver que la última versión 5.4.0-14.17 se ha fusionado con la versión estable 5.4.18:
http://changelogs.ubuntu.com/changelogs/pool/main/l/linux-5.4/linux-5.4_5.4.0-14.17/changelog

Parece que la detección automática adecuada en todas las distribuciones es casi imposible. Veo tres opciones:

  • Hacer nada.
  • Opte por la solución alternativa.
  • Haga la opción de exclusión voluntaria.

O deshabilite la preferencia asíncrona de forma predeterminada en 5.3.xy 5.4.x, y permita que los usuarios la habiliten en tiempo de ejecución.

https://github.com/golang/go/issues/37436#issuecomment -591237929 establece que deshabilitar la preferencia asíncrona no es una solución adecuada, ¿verdad?

No estrictamente hablando, pero no hubo informes del problema antes de que aterrizara la preferencia asincrónica.

En realidad, ¿podría el tiempo de ejecución bifurcar un proceso secundario en el inicio (para 5.3.xy 5.4.x) que desencadena el error y habilitar la solución si lo hace? IIRC hay un reproductor confiable, consulte https://github.com/golang/go/issues/35326#issuecomment -558690446

Deshabilitar la preferencia asincrónica es una distracción. Los programas que se ejecutan en núcleos defectuosos todavía están dañados. Es solo que la ruptura se muestra como una corrupción de memoria extraña en lugar de un error sobre la ejecución de un límite de mlock que apunta a las versiones del kernel. Si bien obviamente queremos solucionar el problema por completo, creo que, dada la opción de un error claro o una corrupción de memoria aleatoria, siempre deberíamos elegir el error claro.

Estoy de acuerdo en que la detección de versiones del kernel es terrible, es solo que no conocemos ninguna otra opción. Si alguien tiene alguna sugerencia al respecto, sería muy útil.

Una cosa que podríamos hacer es agregar una configuración GODEBUG para deshabilitar mlock ing la pila de señales. Eso le daría a la gente una solución que se centra en el problema real. Podemos mencionar esa configuración en el mensaje de error. Me temo que hará que las personas activen la configuración tanto si tienen un kernel parcheado como si no. Pero al menos le dará a las personas que realmente tienen un kernel parcheado una forma de solucionar este problema. CC @aclements

En realidad, ¿podría el tiempo de ejecución bifurcar un proceso secundario en el inicio (para 5.3.xy 5.4.x) que desencadena el error y habilitar la solución si lo hace? IIRC hay un reproductor confiable, vea # 35326 (comentario)

Es una idea interesante, pero creo que, en este caso, la prueba es demasiado cara para ejecutar al inicio para cada programa de Go.

Es posible que me haya perdido algo (¡este hilo se hizo largo y rápido!), Pero ¿cuál es la desventaja o la dificultad de simplemente aumentar el límite de mlock? Hay pocas razones para no solo configurarlo en ilimitado, pero incluso si no desea hacer eso, solo necesita 4 KiB por hilo, por lo que solo 64 MiB es literalmente más que el tiempo de ejecución de un solo proceso es capaz de bloquear . AFAIK, la mayoría de las distribuciones lo dejan ilimitado por defecto. La única excepción notable que conozco es Docker, que lo establece en (creo) 64 KiB de forma predeterminada, pero esto se puede generar pasando --ulimit memlock=67108864 a Docker.

Parece que ya tenemos una solución bastante simple. ¿Hay algo que impida que la gente haga esto?

El punto del problema es que no debería tener que aplicar una solución manual, si es posible. Parece una regresión en 1.14.

No se puede arreglar en el lado de la biblioteca de Docker: https://github.com/docker-library/golang/issues/320

El problema con la solución alternativa ulimit es que es una bomba de tiempo. Actualmente, ningún proceso automatizado necesita aumentar el ulimit con Go 1.13. Cualquiera para quien Go 1.14 falla inmediatamente después de la actualización lo notará y lo arreglará.

El escenario más interesante es lo que sucede si alguien usa una versión antigua de un kernel que no está afectado, y en algún momento cambia el kernel a uno nuevo que sí lo está. De repente, las cosas comenzarán a romperse, pero como Go es la capa de la aplicación y el kernel es la capa del sistema operativo, llevará tiempo hacer la conexión y encontrar una solución. La pregunta es cuál será el costo.


Sin embargo, lo que no está claro de inmediato es si solo el compilador de Go o todas las aplicaciones creadas por Go también tienen problemas. Si solo es el compilador, es un caso afortunado y las consecuencias pueden ser contenidas. Sin embargo, si todas las aplicaciones de Go creadas con 1.14 tienen una tendencia a entrar en pánico, esto realmente podría dañar la portabilidad binaria prediseñada, porque de repente mi código podría no funcionar en un sistema diferente (eso es en realidad completamente válido, solo usa un kernel diferente esquema de control de versiones).

Sin embargo, lo que no está claro de inmediato es si solo el compilador de Go o todas las aplicaciones creadas por Go también tienen problemas.

El error del kernel de Linux ni siquiera es específico de Go. Si lo entiendo correctamente, afectará a cualquier programa, ¡incluso a uno escrito en C! - que utiliza los registros XMM o YMM y puede recibir señales. Los programas Go por debajo de 1.14 resultan ser _más_ severamente afectados que muchos otros programas porque usan señales internamente para la preferencia de goroutine, y es por eso que el tiempo de ejecución de Go 1.14 incluye la solución mlock .

El error del kernel de Linux ni siquiera es específico de Go.

Sí, pero mi kernel está parcheado, pero Go todavía entra en pánico :)

@aclements

La única excepción notable que conozco es Docker, que lo establece en (creo) 64 KiB de forma predeterminada, pero esto se puede generar pasando --ulimit memlock = 67108864 a Docker.

Parece que ya tenemos una solución bastante simple. ¿Hay algo que impida que la gente haga esto?

Por desgracia sí. En nuestro caso aquí, no podemos decirle a nuestros clientes que reconfiguren sus contenedores Docker. Hay demasiados y son sensibles a los cambios ambientales en sus configuraciones; de hecho, es por eso que decidimos entregar la aplicación en un contenedor de ventana acoplable, de modo que la fachada de una herramienta de aislamiento aliviaría la preocupación por cambiar las opciones de configuración. Cambiar el contenido del contenedor está bien, pero la forma en que invocamos el contenedor puede no ser tan buena.

@aclements

Hay pocas razones para no solo configurarlo en ilimitado, pero incluso si no desea hacer eso, solo necesita 4 KiB por hilo, por lo que solo 64 MiB es literalmente más que el tiempo de ejecución de un solo proceso es capaz de bloquear . AFAIK, la mayoría de las distribuciones lo dejan ilimitado por defecto.

Ese no parece ser el caso: este es un Ubuntu LTS con solo 6 KB en el espacio de bloqueo:

~$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 3795
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 3795
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.6 LTS
Release:    16.04
Codename:   xenial
~$ uname -a
Linux bastion0 4.4.0-174-generic #204-Ubuntu SMP Wed Jan 29 06:41:01 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

¿Cuál es el contenido de /proc/version para un kernel de ejemplo que está parcheado para funcionar correctamente pero para el que Go está produciendo actualmente el error mlock ? Gracias.

@ucirello ¿Está viendo algún problema al ejecutar programas de Go en el sistema que describe?

$ cat /proc/version
Linux version 5.3.0-40-generic (buildd@lcy01-amd64-026) (gcc version 9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2)) #32-Ubuntu SMP Fri Jan 31 20:24:34 UTC 2020

Quizás podríamos usar la fecha registrada en /proc/version como una señal adicional. Probablemente debería ser específico para el lanzamiento, lo cual es un dolor. Pero todo es doloroso.

Parece que la discusión gira en torno a aceptar más falsos positivos o falsos negativos. He aquí un resumen:

Falso positivo: la solución alternativa se habilita en un kernel parcheado.

  • Reproducible. Se pueden mostrar instrucciones.
  • Parece una regresión.
  • Difícil de arreglar en ciertos entornos.
  • Go binary puede ejecutarse en algunos entornos, pero no funciona en otros.

Falso negativo: la solución alternativa no está habilitada en un kernel sin parche.

  • La falla solo ocurre en raras ocasiones, especialmente si la preferencia asincrónica está deshabilitada.
  • Posiblemente graves consecuencias debido a la corrupción de la memoria.
  • Difícil de depurar.

@ianlancetaylor No veo ningún problema en el sistema descrito, pero por lo que deduzco, esto podría ser una coincidencia, es decir, el mensaje de error dice que debería actualizar más allá de 5.3.15, 5.4.2 o 5.5 y este es un 4.4.x caja.

En cualquier caso, lo que quería resaltar es que la suposición de que la mayoría de las distribuciones entregan ulimit -l con 64M parece incorrecta. Esta es una caja de Linux cuyo ulimit -l es 64 K , y es una instalación estándar.

¿Hay alguna forma de detectar la configuración ulimit y evitar el bloqueo si no se puede aplicar la solución? ¿De esta manera aún podríamos mejorar la situación pero no causar nuevos choques? En su lugar, podríamos imprimir una advertencia sobre posibles daños en la memoria.

¿Hay alguna forma de detectar la configuración ulimit y evitar el bloqueo si no se puede aplicar la solución?

En efecto, el código actual ya está detectando la configuración ulimit. No lo consulta directamente, pero detecta cuándo se encuentra con él, por lo que está imprimiendo ese mensaje de error en particular que le pide al usuario que active el ulimit. Si algo más sale mal al bloquear, en realidad imprimirá un mensaje diferente. El bloqueo es intencional porque lo consideramos preferible a la corrupción de memoria aleatoria.

En cualquier caso, lo que quería resaltar es que la suposición de que la mayoría de las distribuciones entregan ulimit -lwith 64M parece incorrecta. Esta es una caja de Linux cuyo ulimit -l es 64K, y es una instalación estándar.

@ucirello , gracias por ese dato. No tengo una caja de Ubuntu a mano, pero hice la depuración original en una instalación de Ubuntu y podría haber jurado que no tenía un conjunto ulimit. ¿Definitivamente esto no está en un contenedor?

@ianlancetaylor He creado un script rápido y sucio para verificar lo que informa uname: https://gist.github.com/Tasssadar/7424860a2764e3ef42c7dcce7ecfd341

Aquí está el resultado de las pruebas de Debian actualizadas (bueno, -ish):

tassadar<strong i="9">@dorea</strong>:~/tmp$ go run gouname.go 
real uname
Linux dorea 5.4.0-3-amd64 #1 SMP Debian 5.4.13-1 (2020-01-19) x86_64 GNU/Linux

our uname
sysname Linux
nodename dorea
release 5.4.0-3-amd64  <-- used by go
version #1 SMP Debian 5.4.13-1 (2020-01-19)
machine x86_64
domainname (none)

Dado que Go solo usa la cadena de lanzamiento, la verificación de la versión del parche básicamente no funciona en ningún otro lugar excepto en los kernels de vainilla: tanto Debian como RHEL / CentOS (que, afortunadamente, tiene un kernel demasiado antiguo) lo hacen de esta manera, mantienen el .0 y especifican el versión de parche real más tarde. Desafortunadamente, no usan el mismo formato para version .

EDITAR: y para hacerlo aún más incómodo, Ubuntu no pone el número de parche en uname en absoluto, aunque probablemente tengan todas las correcciones incorporadas. ¿Quizás el mejor curso de acción es hacer de esto una advertencia en lugar de un bloqueo? En este punto, la mayoría de los núcleos probablemente ya estén actualizados de todos modos.

El bloqueo es intencional porque lo consideramos preferible a la corrupción de memoria aleatoria.

@aclements Hay una pequeña falla en este argumento: el problema no son los verdaderos positivos que se encuentran en el ulimit, sino los falsos positivos que no tendrían corrupción de memoria sin la solución.

@aclements

¿Definitivamente esto no está en un contenedor?

Estoy 100% seguro de que no es un contenedor. Sin embargo, es una máquina virtual.

$ sudo virt-what
xen
xen-hvm

@ucirello , gracias por ese dato. No tengo una caja de Ubuntu a mano, pero hice la depuración original en una instalación de Ubuntu y podría haber jurado que no tenía un conjunto ulimit. ¿Definitivamente esto no está en un contenedor?

Como un punto de datos diferente, mi sistema principal de Ubuntu Eoan tiene 64 MB configurado de forma predeterminada en ulimit -l .

@ucirello No hay ningún problema en los kernels de Linux 4.4.x. El error apareció por primera vez en la versión 5.2 del kernel.

@ianlancetaylor - gracias por la información. Supongo que entonces interpreté mal el mensaje de error. No sabía de este hecho, y el mensaje de error me hizo creer que los nuevos binarios serían incompatibles con los núcleos más antiguos.

Los programas Go solo informarán el mensaje de error en los núcleos con un número de versión que indique que pueden tener el problema.

Aquí hay algo que podríamos hacer:

  1. Use uname para verificar la versión del kernel en busca de un kernel vulnerable, como lo hacemos hoy.
  2. Si el kernel es vulnerable según la versión, lea /proc/version .
  3. Si /proc/version contiene la cadena "2020" , suponga que el núcleo está parcheado.
  4. Si /proc/version contiene la cadena "gcc version 8" asuma que el kernel funciona incluso si está parcheado (ya que el error solo ocurre cuando el kernel se compila con GCC 9 o posterior).
  5. De lo contrario, llame a mlock en pilas de señales como lo hacemos hoy en kernels vulnerables.

El objetivo de esto es reducir la cantidad de veces que los programas Go se quedan sin espacio mlock .

¿Alguien sabe de algún kernel sin parche que pueda tener la cadena "2020" en /proc/version ?

Por seguridad, probablemente deberíamos intentar identificar los momentos en los que se parcheó el kernel para las principales distribuciones. ¿Hay alguien que pueda identificar eso para alguna distribución en particular? Gracias.

No estoy seguro de si esto es útil en absoluto, pero aparentemente Ubuntu hace que la versión estándar del kernel esté disponible para aquellos que buscan:

$ cat /proc/version_signature
Ubuntu 5.3.0-1013.14-azure 5.3.18

@jrockway Gracias, el problema no es que no tengamos la versión del kernel, es que Ubuntu está usando una versión del kernel que tiene el error, pero Ubuntu ha aplicado un parche para el error, por lo que el kernel realmente funciona, pero no No sé cómo detectar ese hecho.

Agregando a la heurística de coincidencia de cadenas de @ianlancetaylor , también puede verificar /proc/version para
5.3.x && x >= 15 || 5.4.x && x >= 2 (no es un código real, pero entiendes la idea)

Gracias, ya lo comprobamos en los resultados de uname .

Me refiero a https://github.com/golang/go/issues/37436#issuecomment -591503305:

release 5.4.0-3-amd64  <-- used by go
version #1 SMP Debian 5.4.13-1 (2020-01-19) <-- has actual version

EDITAR: En Ubuntu, puede marcar /proc/version_signature como sugerí.

Ah, lo siento, me perdí eso. Entonces, de acuerdo con ese comentario en algunos sistemas, el campo release y el campo version devueltos por uname difieren en la versión del kernel que informan. Actualmente verificamos el campo release pero no el campo version .

El archivo /proc/version tiene de nuevo un conjunto de información diferente.

Mi sistema Ubuntu tiene /proc/version pero no tiene /proc/version_signature .

@bbarenblat recopiló amablemente uname y / proc / version de varias versiones de varias distribuciones para ver cómo se ven en la naturaleza (agregué algunas de las mías):

Debian inestable:

$ uname -v
#1 SMP Debian 5.3.9-3 (2019-11-19)
$ uname -r
5.3.0-2-amd64
$ cat /proc/version
Linux version 5.3.0-2-amd64 ([email protected]) (gcc version 9.2.1 20191109 (Debian 9.2.1-19)) #1 SMP Debian 5.3.9-3 (2019-11-19)

Debian 10.3 (actual estable):

$ uname -v
#1 SMP Debian 4.19.98-1 (2020-01-26)
$ uname -r
4.19.0-8-amd64
# cat /proc/version
Linux version 4.19.0-8-amd64 ([email protected]) (gcc version 8.3.0 (Debian 8.3.0-6)) #1 SMP Debian 4.19.98-1 (2020-01-26)

Debian 7 (muy antiguo):

$ uname -v
#1 SMP Debian 3.2.78-1
$ uname -r
3.2.0-4-amd64
$ cat /proc/version
Linux version 3.2.0-4-amd64 ([email protected]) (gcc version 4.6.3 (Debian 4.6.3-14) ) #1 SMP Debian 3.2.78-1

Debian "en algún lugar más allá de estable, con el paquete inestable ocasional":

$ uname -v
#1 SMP Debian 4.19.67-2+deb10u1 (2019-09-20)
$ uname -r
4.19.0-6-amd64
$ cat /proc/version
Linux version 4.19.0-6-amd64 ([email protected]) (gcc version 8.3.0 (Debian 8.3.0-6)) #1 SMP Debian 4.19.67-2+deb10u1 (2019-09-20)

Ubuntu 19.10:

$ uname -v
#32-Ubuntu SMP Fri Jan 31 20:24:34 UTC 2020
$ uname -r
5.3.0-40-generic
$ cat /proc/version  
Linux version 5.3.0-40-generic (buildd@lcy01-amd64-026) (gcc version 9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2)) #32-Ubuntu SMP Fri Jan 31 20:24:34 UTC 2020

Ubuntu 19.10 con kernel de GCP (esto realmente es 5.3.0):

$ uname -v
#9-Ubuntu SMP Mon Nov 11 09:52:23 UTC 2019
$ uname -r
5.3.0-1008-gcp
$ cat /proc/version
Linux version 5.3.0-1008-gcp (buildd@lgw01-amd64-038) (gcc version 9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2)) #9-Ubuntu SMP Mon Nov 11 09:52:23 UTC 2019

Ubuntu 19.10 con kernel construido a mano:

$ uname -v
#36 SMP Wed Feb 26 20:55:52 UTC 2020
$ uname -r
5.3.10
$ cat /proc/version
Linux version 5.3.10 (austin@austin-dev-ubuntu) (gcc version 9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2)) #36 SMP Wed Feb 26 20:55:52 UTC 2020

CentOS 7.7:

$ uname -v
#1 SMP Fri Dec 6 15:49:49 UTC 2019
$ uname -r
3.10.0-1062.9.1.el7.x86_64
$ cat /proc/version
Linux version 3.10.0-1062.9.1.el7.x86_64 ([email protected]) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) ) #1 SMP Fri Dec 6 15:49:49 UTC 2019

@aclements Estoy un poco confundido acerca de cuál de los kernels que publicó necesita la solución alternativa y cuáles ya están parcheados. Quizás podrías hacer anotaciones en tu publicación.

El problema es que si se encuentra dentro de los rangos de versiones potencialmente malas, es posible que se vea afectado, si está fuera del rango de versiones, está a salvo.
Cuando se encontró la corrupción inicial, inmediatamente retiramos el parche, lo probamos y lo implementamos. Entonces nuestro kernel estaba 100% dentro del rango malo pero parcheado. Estar fuera del rango significa que está seguro, pero dentro del rango no puede probar que el error existe sin probarlo. (En otras palabras: los falsos positivos ocurrirán por diseño)

Ahora mismo estoy construyendo otro kernel de ubuntu parcheado con números de versión ascendentes

  • make kernelversion
  • parche debian{,.master}/{changelog,control} con esta versión

El software que depende de la versión del kernel es la razón por la que a las distribuciones les gusta mantenerlo estable: si una actualización del número de versión puede dañar el software que funcionaba antes, entonces es mejor no cambiar la versión (¡pero aún aplicar los parches!).

No estoy feliz de lanzar un nuevo kernel solo por golang 1.14, pero creo que funcionará.
Desalentaría a todos a enviar binarios de golang 1.14 fuera de entornos controlados.

La publicación de

Creo que debería ser opcional para evitar todos los falsos positivos. Por ejemplo, agregue GOWORKAROUNDS env var boolean o con una lista de soluciones o para habilitar la heurística para intentar encontrarlas.

Esta sería la solución menos intrusiva de la OMI.

@ fcuello-fudo el problema es que si la solución alternativa no está habilitada en un kernel defectuoso, los síntomas son muy oscuros.

¿Qué tal si reutilizamos el concepto "contaminado" del kernel de Linux? El tiempo de ejecución de Go seguiría detectando kernels defectuosos y aplicaría la solución alternativa de mlock, pero se marca a sí mismo contaminado si mlock falla (y no se bloquea). Luego, asegúrese de agregar una nota a cualquier pánico y arroje mensajes si se establece la marca de corrupción.

La ventaja es que se evitan los fallos de falsos positivos, al tiempo que proporcionan una indicación clara en caso de que un kernel defectuoso provoque un fallo.

La desventaja es que un kernel defectuoso puede dañar silenciosamente la memoria, sin causar un bloqueo visible.

@ fcuello-fudo el problema es que si la solución alternativa no está habilitada en un kernel defectuoso, los síntomas son muy oscuros.

¿Y dejarlo habilitado de forma predeterminada, pero aún sería útil deshabilitar las soluciones si el usuario lo desea?

@howardjohn (desarrollador principal de Istio de Google) en https://github.com/istio/istio/issues/21672 :

Mi kernel en mi máquina personal no está parcheado. Pero realmente no importa lo que tenga mi máquina, enviamos Istio a miles de usuarios. No puedo controlar en qué máquina lo ejecutan, y me encantaría no tener que restringir eso a algún subconjunto de versiones del kernel

El proyecto Prometheus también está frenando su actualización go1.14: https://github.com/prometheus/golang-builder/pull/85#issuecomment -592082645

Encontré este problema al ejecutar aplicaciones go en un clúster de Kubernetes autohospedado. Pude permitir que la solución _mlock_ surta efecto aumentando el ulimit relevante. Sin embargo, dado que el proceso para cambiar ulimits para contenedores Docker que se ejecutan en Kubernetes no es exactamente fácil de encontrar, podría ayudar a otra persona a poner los detalles aquí.

  1. Actualice /etc/security/limits.conf para incluir algo como
* - memlock unlimited
  1. Actualizar /etc/docker/daemon.json para incluir
"default-ulimits": { "memlock": { "name": "memlock", "hard": -1, "soft": -1 } }
  1. Reinicie Docker / Kubernetes, vuelva a activar sus pods.

  2. Ingrese a un contenedor en ejecución y verifique que el ulimit se haya incrementado:

$ kubectl exec -it pod-name -- /bin/sh
/ # ulimit -l
unlimited

Es posible que pueda salirse con la suya usando algo más sutil que el martillo _unlimited_; para mí, un límite de 128 KB (131072) parecía funcionar.

también se encuentra con este problema al intentar crear una imagen de Docker para https://github.com/RTradeLtd/Temporal on go 1.14

Y la pila sigue amontonándose. Mira, esta es la razón por la que me enojé al comienzo de este hilo (que fue un gran error de mi parte, estoy de acuerdo). A pesar de que hice un gran esfuerzo para explicar y proporcionar una reproducción de que esto es un bloqueador, me cerraron para no interferir con el lanzamiento. Incluso después de que quedó claro que no es un problema de Docker.

Ahora estamos en un espacio mucho peor ya que varios proyectos están en la lista negra de Go 1.14. Actualmente, este error está programado para corregirse solo en Go 1.15. Con base en los problemas vinculados anteriormente, ¿estamos seguros de que es una buena idea posponer esto por 8 meses? Creo que sería bueno reconocer el desastre e intentar solucionarlo en una versión de parche, no esperar a que se muerdan más proyectos.

Sí, soy consciente de que solo estoy regañando a la gente aquí en lugar de arreglarlo yo mismo. Lo siento, no puedo contribuir de manera más significativa, simplemente no quiero fragmentar el ecosistema. Los módulos Go ya fueron un golpe para muchos proyectos, no nos doblemos con otra peculiaridad que las herramientas deben conocer.

Ian Lance-Taylor ha dicho que la solución se actualizará una vez que haya una: https://groups.google.com/d/msg/golang-dev/_FbRwBmfHOg/mmtMSjO1AQAJ

@lmb Oh, es muy bueno escucharlo, gracias por el enlace.

FYI: Ubuntu 20.04 probablemente se enviará 5.4.0, lo que significa que desde fines del próximo mes
Ubuntu LTS y golang más recientes no funcionarán juntos desde el primer momento.

Lorenz Bauer [email protected] schrieb am Fr., 6. März 2020, 12:42:

Ian Lance-Taylor ha dicho que la solución se publicará una vez que haya
uno: https://groups.google.com/d/msg/golang-dev/_FbRwBmfHOg/mmtMSjO1AQAJ

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/golang/go/issues/37436?email_source=notifications&email_token=AAAO66R6S5VOWQBKETLI5UDRGDORJA5CNFSM4K3GBRRKYY3PNVWWK3TUL52HS4DFVREXG43VMDVBWCI63 ,
o darse de baja
https://github.com/notifications/unsubscribe-auth/AAAO66SH6J4M75WDJ5GO7HTRGDORJANCNFSM4K3GBRRA
.

@karalabe en términos tan enérgicos como puedo reunir, no estabas "cerrado para no interferir con el lanzamiento". Josh, quien originalmente cerró el problema, no está en el equipo de Go en Google (es decir, no es un tomador de decisiones) ni yo. Inicialmente asumimos que el proyecto Docker podría (y debería) mitigar el problema en su compilación. Cuando quedó claro que no podían, lo mencioné rápidamente en golang-dev.

Además, fui el primero en notar que el problema proviene del kernel de su host, no del módulo Docker. No mencionaste que estás en Ubuntu hasta que se lo señalé.

Creo que nos debes una disculpa más, después de esa nota.

EDITAR: También le pedí que eliminara los rastros de pila goroutine (comenzando goroutine x [runnable] ) de su informe, ya que hacen que la página sea difícil de leer / navegar. [Actualización: Russ ha eliminado las pilas].

Todos deben tener en cuenta que la comunicación exitosa es difícil y una habilidad que uno necesita practicar. Las emociones pueden trabajar en nuestra contra y obstaculizar nuestro objetivo de una comunicación exitosa, yo mismo he estado allí. Sí, ha habido una violación del código de conducta y señalarlo es bueno. Una disculpa voluntaria también es útil. Ahora intentemos asegurarnos de que cada publicación tenga un impacto neto positivo en la colaboración y la solución de este problema.

@rtreffer ¿Sabe si la versión del kernel planificada para Ubuntu 20.04 incluirá el parche? Parece que fue seleccionado en el kernel 5.3.0 de Ubuntu (https://kernel.ubuntu.com/git/ubuntu/ubuntu-eoan.git/commit/?id=59e7e6398a9d6d91cd01bc364f9491dc1bf2a426). Supongo que también está en su kernel 5.4.0, pero sería bueno estar seguro. Gracias.

@rtreffer ¿Sabe si la versión del kernel planificada para Ubuntu 20.04 incluirá el parche? Parece que fue seleccionado en el kernel 5.3.0 de Ubuntu (https://kernel.ubuntu.com/git/ubuntu/ubuntu-eoan.git/commit/?id=59e7e6398a9d6d91cd01bc364f9491dc1bf2a426). Supongo que también está en su kernel 5.4.0, pero sería bueno estar seguro. Gracias.

Se incluirá en el kernel de lanzamiento para 20.04, sí:

(master)mwhudson<strong i="9">@anduril</strong>:~/src/upstream/linux-2.6$ git log -1 --oneline ad9325e9870914b18b14857c154a0fee0bd77287
ad9325e98709 x86/fpu: Don't cache access to fpu_fpregs_owner_ctx
(master)mwhudson<strong i="10">@anduril</strong>:~/src/upstream/linux-2.6$ git tag --contains ad9325e9870914b18b14857c154a0fee0bd77287
Ubuntu-5.4-5.4.0-10.13
Ubuntu-5.4-5.4.0-11.14
Ubuntu-5.4-5.4.0-12.15
Ubuntu-5.4-5.4.0-13.16
Ubuntu-5.4-5.4.0-14.17
Ubuntu-5.4.0-15.18
Ubuntu-5.4.0-16.19
Ubuntu-5.4.0-17.20
Ubuntu-5.4.0-17.21
Ubuntu-5.4.0-8.11
Ubuntu-5.4.0-9.12
Ubuntu-raspi2-5.4-5.4.0-1002.2
Ubuntu-raspi2-5.4.0-1003.3
Ubuntu-raspi2-5.4.0-1004.4

Basado en la discusión con @aclements , @ dr2chase , @ randall77 y otros, nuestro plan para la versión 1.14.1 es:

  • escribir una página wiki que describa el problema
  • continuar usando mlock en una versión del kernel que puede tener errores
  • si mlock falla, anote ese hecho en silencio y continúe ejecutando
  • si vemos un SIGSEGV o SIGBUS inesperado, y mlock falló, entonces, en la pila de fallos, señale a las personas en la página wiki

La esperanza es que proporcione una buena combinación de ejecución correcta en el caso normal y, al mismo tiempo, dirija a las personas sobre núcleos potencialmente defectuosos a información que les ayude a decidir si el problema es su núcleo o su programa o un error en Go.

Esto también se puede combinar con mejores intentos de identificar si un kernel en particular ha sido parcheado, basado en el campo uname version (actualmente solo verificamos el campo release ).

Otra cosa que discutimos: si un mlock falló y estamos a punto de enviarnos una señal, primero toque la pila de señales.

@ianlancetaylor ¡ suena como una gran idea!

Si aún no lo ha considerado: enlace a esa página wiki desde el mensaje de error (potencialmente con una indirección más)

Por ejemplo, iPXE lo hace a través de enlaces como http://ipxe.org/1d0c6539 (su salida está optimizada para ROM de arranque, propiedades inmobiliarias limitadas y similares)

  • escribir una página wiki que describa el problema

  • continuar usando mlock en una versión del kernel que puede tener errores

  • si mlock falla, anote ese hecho en silencio y continúe ejecutando

¿No sería mejor deshabilitar también la preferencia asincrónica? Es cierto que el problema puede ocurrir incluso con asyncpreemptoff = 1, pero el error era tan raro que sin él nadie se dio cuenta durante meses.

¿Hay alguna forma de probar (fuera del tiempo de ejecución de Go) para ver si su kernel está parcheado? Mantenemos nuestros propios núcleos fuera de la distribución, lo que hace que esto funcione incluso.

@gopherbot por favor backport para ir1.14. Es un problema grave sin solución.

Problemas de backport abiertos: # 37807 (para 1.14).

Recuerde crear los CL (s) de selección selectiva tan pronto como el parche se envíe al maestro, de acuerdo con https://golang.org/wiki/MinorReleases.

@nemith hay un reproductor de C aquí: https://github.com/golang/go/issues/35326#issuecomment -558690446

@ randall77 @aarzilli Tras considerarlo, en realidad no creo que sea una gran idea agregar mitigaciones parciales adicionales como tocar la página de la pila de señales o deshabilitar la preferencia asincrónica. Es un error de nivel de kernel que puede afectar a cualquier programa que reciba una señal. Las personas que ejecutan un kernel con errores deben actualizar el kernel de una forma u otra. El uso de mlock es una mitigación confiable que siempre debería funcionar y, como tal, es razonable intentarlo. Tocar la pila de señales antes de enviar una señal de preferencia, o deshabilitarla por completo, no es una mitigación confiable. Creo que no deberíamos recurrir a una mitigación poco fiable; debemos decirle al usuario que actualice el kernel.

Las personas que no pueden actualizar el kernel tienen la opción de ejecutar GODEBUG=asyncpreemptoff=1 , que será una mitigación parcial tan efectiva como las otras dos.

Creo que no deberíamos recurrir a una mitigación poco fiable; debemos decirle al usuario que actualice el kernel.

Estoy de acuerdo con usted si el error siempre se manifiesta en un accidente. Pero no es así, simplemente corrompe la memoria al azar. Tal vez se bloquee, pero tal vez simplemente corrompe aleatoriamente los datos del programa y sigue ejecutándose. Creo que nos corresponde a nosotros tomar todas las medidas que podamos para evitar la corrupción de datos, incluso si eso significa que no enviaremos mensajes sobre la actualización requerida del kernel con tanta frecuencia.

Es una decisión de ahora contra más tarde. Podemos intentar evitar la corrupción de datos ahora tocando las páginas de señales antes de su uso. O podemos intentar evitar la corrupción más tarde enviando un mensaje al usuario en caso de un bloqueo. No podemos elegir ambos.

Desearía que hubiera una forma de poder enviar mensajes cuando detectamos una falla de mlock, sin fallar, y luego mitigar tocando las páginas. No creo que el programa Go pueda hacer eso en stdout / stderr, desafortunadamente. ¿Quizás podríamos lanzar algo en el syslog? Solo ayudaría a aquellos que echan un vistazo al syslog, que probablemente no sea muchos.

Punto justo.

¿Qué tal publicar un mensaje sobre la instalación? Eso implica un cambio para instalar los procedimientos para sus versiones binarias y las distribuciones, pero eso le permitiría ejecutar el reproductor para probar definitivamente el error.

@networkimprov Esa es una buena idea, pero dado que la gente envía programas compilados a través de máquinas que pueden tener diferentes versiones de kernel, creo que también necesitamos el enfoque descrito anteriormente.

El cambio https://golang.org/cl/223121 menciona este problema: runtime: don't crash on mlock failure

Envié https://golang.org/cl/223121. Sería útil si las personas que tienen problemas con 1.14 pudieran ver si ese cambio soluciona el problema. Gracias.,

Bueno, @ randall77 / @ianlancetaylor , tiendo a no estar de acuerdo con que este sea un problema de golang. Golang descubrió el problema de la corrupción de la memoria, pero es un error del kernel muy grave.

Como tal, debería escalar a través de las rutas de su kernel.
Distributions recogió el parche y lo envió. Fue respaldado. Cada nueva instalación obtendrá un kernel no afectado.
Si lanza su propio kernel, debe hacerlo usted mismo. Como siempre.

Sea útil para los usuarios que lo acierten y sea lo más útil posible.
Pero no creo que sea responsabilidad de Golang corregir un error del kernel o incluso obligar a los usuarios a aplicar el parche.

@rtreffer Eso es lo que estamos tratando de hacer: ser lo más útiles posible.

En kernels con errores, los programas de Go compilados con Go 1.14 se comportaron de manera impredecible y mala. No queremos hacer eso ni siquiera en un kernel con errores. Si un programa fallara rápida y limpiamente, eso sería una cosa. Pero lo que vimos fue la corrupción de la memoria que conducía a errores oscuros. Vea # 35326, entre otros.

¿Crees que deberíamos tomar alguna acción diferente a la que estamos haciendo ahora?

@rtreffer Bueno, sorta. Tenemos algunos núcleos de producción 5.2 que no se ven afectados ya que no están compilados con gcc9 y también podríamos parchear fácilmente la solución en nuestra línea de kernel sin afectar nada más y estar bien. El error del kernel no existe en nuestro entorno y la actualización de las versiones principales requiere muchas más pruebas y una implementación cuidadosa en toda la flota, por lo que simplemente "actualizar su kernel" no es una buena situación.

Por otro lado, la solución alternativa basada en los números de versión del kernel hizo que nos moviéramos a mlocks que DID fallaron debido a problemas de ulimit. Eso no es un error del kernel.

Dicho esto, no estoy seguro de que haya una solución mejor aquí y el equipo de Go probablemente tomó la decisión correcta.

@ianlancetaylor tal vez podría enviar el reproductor C en las versiones fuente y binarias, y hacer referencia a eso en la página wiki como una forma de examinar cualquier kernel.

¿Qué tal publicar un mensaje sobre la instalación? Eso implica un cambio para instalar los procedimientos para sus versiones binarias y las distribuciones, pero eso le permitiría ejecutar el reproductor para probar definitivamente el error.

Cualquier distribución que esté prestando suficiente atención para hacer esto simplemente parcheará su kernel, seguramente.

@ianlancetaylor Estoy totalmente de acuerdo con el camino a seguir, el parche y la página wiki se ven geniales.

Quería enfatizar que la corrupción no es culpa de Golangs o error para empezar y las distribuciones están enviando kernels reparados. Ya debería estar desapareciendo.

Como resultado, no creo que se necesite nada más que las sugerencias sugeridas (wiki + pánico).

@rtreffer Genial, gracias.

El cambio https://golang.org/cl/223417 menciona este problema: [release-branch.go1.14]runtime: don't crash on mlock failure

Solo para aclarar, según lo que dice la wiki, si mlock falla en 1.14.1, ¿eso significa que el programa es vulnerable a la corrupción de la memoria?

Gracias

@ smasher164 No necesariamente. Ya no imprimimos el mensaje "mlock fail" cuando falla la llamada mlock. En cambio, nos limitamos a salvar el hecho de que falló. si su programa falla, imprimimos el hecho de que el mlock falló en el texto del error. Lo que significa "creemos que su kernel podría tener errores. Probamos la solución alternativa de mlock y falló. Ejecutamos su programa de todos modos y terminó fallando". Tal vez se debió al error del kernel, tal vez solo sea un error en su programa.

@ randall77 Gracias por responder. Entonces, ¿es seguro decir que si mlock falló y el programa no se bloquea al tocar la pila antes de enviar una señal de preferencia, esa corrupción de memoria relacionada con la preferencia asíncrona no existe en el programa?

Lamentablemente no. Si mlock falla y tiene un kernel defectuoso, es posible que se esté dañando la memoria. El hecho de que el programa no se bloquee no significa que no haya corrupción en alguna parte. La falla es un efecto secundario de la corrupción de la memoria; solo la falla de mlock no causará una falla. (Solíamos hacer eso en 1.14. Esa es una de las cosas que cambiamos para 1.14.1).
Incluso si desactiva la preferencia asincrónica, es posible que se sigan produciendo daños en la memoria. Solo a un ritmo más bajo, ya que su programa probablemente todavía esté recibiendo otras señales (temporizadores, etc.).

@ smasher164 Háganos saber si encuentra que la página wiki https://golang.org/wiki/LinuxKernelSignalVectorBug no es clara. Gracias.

¿Cómo puedo excluirme de esto?

Estoy dentro de un contenedor lxc sin privilegios creado por lxd , por lo que tiene el mismo kernel que el host, pero no puede establecer límites para todo el sistema:

# container
$ uname -a
Linux runner-33-project-447-concurrent-0-job-25150 5.4.0-31-generic #35-Ubuntu SMP Thu May 7 20:20:34 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$ /proc/version_signature
/proc/version_signature: Permission denied
$ ulimit -l 123456
ulimit: max locked memory: cannot modify limit: Operation not permitted
# host
$ uname -a
Linux gitlab-ci-runner-lxd-2 5.4.0-31-generic #35-Ubuntu SMP Thu May 7 20:20:34 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$ cat /proc/version_signature 
Ubuntu 5.4.0-31.35-generic 5.4.34

Según https://github.com/golang/go/issues/37436#issuecomment -595836976, el host (focal) contiene el parche del kernel.

Go fue construido hace unos días usando go get golang.org/dl/go1.14 y go1.14 download

$ go version
go version go1.14 linux/amd64

Nuevamente: ¿Cómo puedo excluirme de esto?

Tal vez no pueda / no quiera cambiar los límites de todo el sistema, ya que otros programas / canalizaciones se ven afectados y se debe lograr un consenso colectivo para todas estas posibilidades antes de cambiar las opciones de todo el sistema.

Es bueno que tuviéramos tal detección, pero está roto que no podemos optar por no participar fácilmente. Cuando lo sabemos, los núcleos tienen los parches corregidos y la detección es propensa a falsos positivos.

@dionysius Esto se corrigió en 1.14.1 como se describe en https://github.com/golang/go/issues/37436#issuecomment -597360484. Creo que necesita actualizar a una versión más reciente de go: https://godoc.org/golang.org/dl/go1.14.2.

Intentaré luego cargar explícitamente la versión go, esperaba que go get golang.org/dl/go1.14 cargara la última versión 1.14. Informaré de vuelta.

Editar, parece que 1.14.3 es el último 1.14 a partir de hoy

Actualización: se ve bien con go get golang.org/dl/go1.14.3 , inesperado que sin un parche que no esté cargando la última, es bueno saberlo (de lo contrario, nunca habría aterrizado en este problema)

Solo un aviso: Go1.15 está a punto de ser lanzado, y ya se lanzó una versión beta, pero el parche temporal aún no se eliminó (hay comentarios pendientes para eliminar en Go1.15).

Creo que es importante eliminar la solución ya que Ubuntu 20.04 LTS usa un kernel 5.4.0 parcheado. Esto significa que cualquier usuario de Ubuntu 20.04 seguirá bloqueando innecesariamente las páginas, y si se ejecuta en un contenedor de la ventana acoplable, esa advertencia se mostrará para cada bloqueo, sin tener en cuenta el hecho de que su kernel no tiene errores. Por lo tanto, esos usuarios podrían ser enviados a una búsqueda inútil tratando de comprender y leer toda esta información, y no tendrá nada que ver con su error, probablemente durante la totalidad del ciclo de vida de Ubuntu 20.04.

@DanielShaulov gracias. ¿Podrías abrir una nueva edición para eso? Éste pertenece al problema en 1.14.

@networkimprov seguro: # 40184

El cambio https://golang.org/cl/243658 menciona este problema: runtime: let GODEBUG=mlock=0 disable mlock calls

El cambio https://golang.org/cl/244059 menciona este problema: runtime: don't mlock on Ubuntu 5.4 systems

¿ Cuándo se lanza

La solución ha estado en todas las versiones desde la versión 1.14.1, que se envió hace meses.

El cambio https://golang.org/cl/246200 menciona este problema: runtime: revert signal stack mlocking

¿Fue útil esta página
0 / 5 - 0 calificaciones