Skip to content

Conversation

@cyphar
Copy link
Contributor

@cyphar cyphar commented Sep 12, 2018

In newer kernels, AppArmor will reject attempts to send signals to a
container because the signal originated from outside of that AppArmor
profile. Correct this by allowing all unconfined signals to be received.

Carry #36822
Fixes #36809
Signed-off-by: Goldwyn Rodrigues rgoldwyn@suse.com
Signed-off-by: Aleksa Sarai asarai@suse.de

@vdemeester
Copy link
Member

cc @AkihiroSuda @jessfraz

@ericchiang
Copy link

ericchiang commented Sep 12, 2018

I tested this on my affected machine by replacing the docker-default profile with the one suggested here: #36809 (comment)

It appears to have worked, and the docker daemon can now kill containers.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to note, this is the first time that the daemon assumes it runs as "unconfined". I don't run it as that profile, so I had to tweak it.

Since this is dynamically generated, maybe we could replace this with:

signal (receive) peer={{.DaemonProfile}}

Then fill that value in with whatever's in /proc/self/attr/current

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a self keyword or something I think

Copy link
Contributor Author

@cyphar cyphar Sep 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will take a look into whether there's a self keyword or if we'd need to actually read attr/current. I completely forgot that we have a daemon profile.

EDIT: I don't think we could use a self keyword actually because we need to reference whatever profile Docker is under. I'll write a patch with .DaemonProfile.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yeah omg that daemon profile is bad but regardless... lgtm :)

@jessfraz
Copy link
Contributor

jessfraz commented Sep 12, 2018

We need to be careful here because the "peer" keyword is only supported on certain versions iirc
Updated: just saw you did that... Should be fine then

@cyphar cyphar force-pushed the apparmor-external-templates branch from 76cce67 to 2d4461b Compare September 12, 2018 15:54
@codecov
Copy link

codecov bot commented Sep 12, 2018

Codecov Report

Merging #37831 into master will decrease coverage by 0.05%.
The diff coverage is n/a.

@@            Coverage Diff             @@
##           master   #37831      +/-   ##
==========================================
- Coverage   36.13%   36.08%   -0.06%     
==========================================
  Files         610      610              
  Lines       45054    48007    +2953     
==========================================
+ Hits        16282    17324    +1042     
- Misses      26532    28324    +1792     
- Partials     2240     2359     +119

@cyphar cyphar force-pushed the apparmor-external-templates branch from 2d4461b to 4822fb1 Compare September 12, 2018 16:05
In newer kernels, AppArmor will reject attempts to send signals to a
container because the signal originated from outside of that AppArmor
profile. Correct this by allowing all unconfined signals to be received.

Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
Signed-off-by: Aleksa Sarai <asarai@suse.de>
@ericchiang
Copy link

I've built and tested this. It works when the docker deamon runs as a profile other than unconstrained.

Before:

$ sudo docker run -d alpine:latest sleep 600
58a1e1b23e17a740c1a7a0f6d7b8e0fa8337fcab59ae7c949f69ba134eda320e
$ sudo docker kill 58a1e1b23e17a740c1a7a0f6d7b8e0fa8337fcab59ae7c949f69ba134eda320e
Error response from daemon: Cannot kill container: 58a1e1b23e17a740c1a7a0f6d7b8e0fa8337fcab59ae7c949f69ba134eda320e: Cannot kill container 58a1e1b23e17a740c1a7a0f6d7b8e0fa8337fcab59ae7c949f69ba134eda320e: unknown error after kill: docker-runc did not terminate sucessfully: container_linux.go:393: signaling init process caused "permission denied"
: unknown

After:

$ sudo docker run -d alpine:latest sleep 600                                                                                                                                                                       
798a35422d6d92855e4d561e7ac9498a26858f2664160f671161ad4794b6bbc8                                                                                                                                                                            
$ sudo docker kill 798a35422d6d92855e4d561e7ac9498a26858f2664160f671161ad4794b6bbc8                                                                                                                                    
798a35422d6d92855e4d561e7ac9498a26858f2664160f671161ad4794b6bbc8

Copy link
Contributor

@mrueg mrueg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has fixed the in-container signaling issues I saw.

@thaJeztah
Copy link
Member

@cyphar sorry for the delay; in the original PR you mentioned that the kernel patch that cause this issue was reverted;

I have since discovered that the corresponding kernel patch that required this change was actually reverted in the upstream kernel. We still have it in the SUSE kernels, so this is still a problem for us, but we can drop this from being merged in upstream Docker (unless the kernel change gets re-merged upstream). However the reason it was reverted is because it broke userspace -- so in theory if it ever gets merged we still won't need to modify the default profile.

Did that change?

@thaJeztah
Copy link
Member

Also ping @justincormack PTAL

@cyphar
Copy link
Contributor Author

cyphar commented Oct 3, 2018

So I just checked the commit history and it looks like the code was never reverted torvalds/linux@cd1dbf7 has been in all kernel versions since 4.14 and there is no revert commit (and git blame shows that commit as the genesis of the current aa_may_signal code). I don't remember who told me it was reverted, but that's clearly not true.

However the kernel code currently has a check that should avoid userspace breakage (which is what this patch is attempting to fix):

static int profile_signal_perm(struct aa_profile *profile,
			       struct aa_label *peer, u32 request,
			       struct common_audit_data *sa)
{
	/* ... */
	if (profile_unconfined(profile) ||
	    !PROFILE_MEDIATES(profile, AA_CLASS_SIGNAL))
		return 0;
	/* ... */
}

Which effectively means that if a profile contains no signal entries then there are no restrictions on signals. But if a profile contains any signal entries then we have to apply this patch so that signals within the same profile and signals from an unconfined profile are allowed.

So why are people seeing this? I think it's because of abstractions/base. Some distributions have entries like the following:

  # Allow unconfined processes to send us signals by default
  signal (receive) peer=unconfined,

  # Allow us to signal ourselves
  signal peer=@{profile_name},

  # Checking for PID existence is quite common so add it by default for now
  signal (receive, send) set=("exists"),

Which will be applied by default in Docker -- so I think it depends strongly on how your distribution is configured whether or not you will hit an issue. If you have signal entries but not these ones, then you'll be in trouble. But we still should include an entry for DaemonProfile because the above doesn't handle that properly...

@cyphar
Copy link
Contributor Author

cyphar commented Nov 14, 2018

/ping

@thaJeztah
Copy link
Member

ping @kolyshkin @justincormack PTAL

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

sorry for the delay, wanted to have a look from @justincormack before going ahead 🤗

lifupan added a commit to lifupan/tests that referenced this pull request May 15, 2019
In newer kernels, AppArmor will reject attempts to send signals to a
container because the signal originated from outside of that AppArmor
profile.

For much info, please see moby/moby#37831.

Fixes:kata-containers#1568

Signed-off-by: lifupan <lifupan@gmail.com>
lifupan added a commit to lifupan/tests that referenced this pull request May 15, 2019
In newer kernels, AppArmor will reject attempts to send signals to a
container because the signal originated from outside of that AppArmor
profile.

For much info, please see moby/moby#37831.

Fixes:kata-containers#1568

Signed-off-by: lifupan <lifupan@gmail.com>
lifupan added a commit to lifupan/tests that referenced this pull request May 15, 2019
In newer kernels, AppArmor will reject attempts to send signals to a
container because the signal originated from outside of that AppArmor
profile.

For much info, please see moby/moby#37831.

Fixes:kata-containers#1568

Signed-off-by: lifupan <lifupan@gmail.com>
lifupan added a commit to lifupan/tests that referenced this pull request May 16, 2019
In newer kernels, AppArmor will reject attempts to send signals to a
container because the signal originated from outside of that AppArmor
profile.

For much info, please see moby/moby#37831.

Fixes:kata-containers#1568

Signed-off-by: lifupan <lifupan@gmail.com>
lifupan added a commit to lifupan/tests that referenced this pull request May 16, 2019
In newer kernels, AppArmor will reject attempts to send signals to a
container because the signal originated from outside of that AppArmor
profile.

For much info, please see moby/moby#37831.

Fixes:kata-containers#1568

Signed-off-by: lifupan <lifupan@gmail.com>
lifupan added a commit to lifupan/tests that referenced this pull request May 16, 2019
In newer kernels, AppArmor will reject attempts to send signals to a
container because the signal originated from outside of that AppArmor
profile.

For much info, please see moby/moby#37831.

Fixes:kata-containers#1568

Signed-off-by: lifupan <lifupan@gmail.com>
cyphar added a commit to cyphar/containerd that referenced this pull request Jan 29, 2021
On newer kernels and systems, AppArmor will block sending signals in
many scenarios by default resulting in strange behaviours (container
programs cannot signal each other, or host processes like containerd
cannot signal containers).

The reason this happens only on some distributions (and is not a kernel
regression) is that the kernel doesn't enforce signal mediation unless
the profile contains signal rules. However because our profies #include
the distribution-managed <abstractions/base>, some distributions added
signal rules -- which results in AppArmor enforcing signal mediation and
thus a regression. On these systems, containers cannot send and receive
signals at all -- meaning they cannot signal each other and the
container runtime cannot kill them either.

This issue was fixed in Docker in 2018[1] but this code was copied
before then and thus the patches weren't carried. It also contains a new
fix for a more esoteric case[2]. Ideally this code should live in a
project like "containerd/apparmor" so that Docker, libpod, and
containerd can share it, but that's probably something to do separately.

In addition, the copyright header is updated to reference that the code
is copied from Docker (and thus was not written entirely by the
containerd authors).

[1]: moby/moby#37831
[2]: moby/moby#41337

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
brandond pushed a commit to brandond/containerd that referenced this pull request Jan 29, 2021
On newer kernels and systems, AppArmor will block sending signals in
many scenarios by default resulting in strange behaviours (container
programs cannot signal each other, or host processes like containerd
cannot signal containers).

The reason this happens only on some distributions (and is not a kernel
regression) is that the kernel doesn't enforce signal mediation unless
the profile contains signal rules. However because our profies #include
the distribution-managed <abstractions/base>, some distributions added
signal rules -- which results in AppArmor enforcing signal mediation and
thus a regression. On these systems, containers cannot send and receive
signals at all -- meaning they cannot signal each other and the
container runtime cannot kill them either.

This issue was fixed in Docker in 2018[1] but this code was copied
before then and thus the patches weren't carried. It also contains a new
fix for a more esoteric case[2]. Ideally this code should live in a
project like "containerd/apparmor" so that Docker, libpod, and
containerd can share it, but that's probably something to do separately.

In addition, the copyright header is updated to reference that the code
is copied from Docker (and thus was not written entirely by the
containerd authors).

[1]: moby/moby#37831
[2]: moby/moby#41337

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
(cherry picked from commit d8572b6)
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
brandond pushed a commit to brandond/containerd that referenced this pull request Jan 29, 2021
On newer kernels and systems, AppArmor will block sending signals in
many scenarios by default resulting in strange behaviours (container
programs cannot signal each other, or host processes like containerd
cannot signal containers).

The reason this happens only on some distributions (and is not a kernel
regression) is that the kernel doesn't enforce signal mediation unless
the profile contains signal rules. However because our profies #include
the distribution-managed <abstractions/base>, some distributions added
signal rules -- which results in AppArmor enforcing signal mediation and
thus a regression. On these systems, containers cannot send and receive
signals at all -- meaning they cannot signal each other and the
container runtime cannot kill them either.

This issue was fixed in Docker in 2018[1] but this code was copied
before then and thus the patches weren't carried. It also contains a new
fix for a more esoteric case[2]. Ideally this code should live in a
project like "containerd/apparmor" so that Docker, libpod, and
containerd can share it, but that's probably something to do separately.

In addition, the copyright header is updated to reference that the code
is copied from Docker (and thus was not written entirely by the
containerd authors).

[1]: moby/moby#37831
[2]: moby/moby#41337

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
(cherry picked from commit d8572b6)
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
dweomer pushed a commit to k3s-io/containerd that referenced this pull request Mar 16, 2021
On newer kernels and systems, AppArmor will block sending signals in
many scenarios by default resulting in strange behaviours (container
programs cannot signal each other, or host processes like containerd
cannot signal containers).

The reason this happens only on some distributions (and is not a kernel
regression) is that the kernel doesn't enforce signal mediation unless
the profile contains signal rules. However because our profies #include
the distribution-managed <abstractions/base>, some distributions added
signal rules -- which results in AppArmor enforcing signal mediation and
thus a regression. On these systems, containers cannot send and receive
signals at all -- meaning they cannot signal each other and the
container runtime cannot kill them either.

This issue was fixed in Docker in 2018[1] but this code was copied
before then and thus the patches weren't carried. It also contains a new
fix for a more esoteric case[2]. Ideally this code should live in a
project like "containerd/apparmor" so that Docker, libpod, and
containerd can share it, but that's probably something to do separately.

In addition, the copyright header is updated to reference that the code
is copied from Docker (and thus was not written entirely by the
containerd authors).

[1]: moby/moby#37831
[2]: moby/moby#41337

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
(cherry picked from commit d8572b6)
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
brandond pushed a commit to brandond/containerd that referenced this pull request Mar 30, 2021
On newer kernels and systems, AppArmor will block sending signals in
many scenarios by default resulting in strange behaviours (container
programs cannot signal each other, or host processes like containerd
cannot signal containers).

The reason this happens only on some distributions (and is not a kernel
regression) is that the kernel doesn't enforce signal mediation unless
the profile contains signal rules. However because our profies #include
the distribution-managed <abstractions/base>, some distributions added
signal rules -- which results in AppArmor enforcing signal mediation and
thus a regression. On these systems, containers cannot send and receive
signals at all -- meaning they cannot signal each other and the
container runtime cannot kill them either.

This issue was fixed in Docker in 2018[1] but this code was copied
before then and thus the patches weren't carried. It also contains a new
fix for a more esoteric case[2]. Ideally this code should live in a
project like "containerd/apparmor" so that Docker, libpod, and
containerd can share it, but that's probably something to do separately.

In addition, the copyright header is updated to reference that the code
is copied from Docker (and thus was not written entirely by the
containerd authors).

[1]: moby/moby#37831
[2]: moby/moby#41337

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
(cherry picked from commit d8572b6)
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
brandond pushed a commit to k3s-io/containerd that referenced this pull request Mar 30, 2021
On newer kernels and systems, AppArmor will block sending signals in
many scenarios by default resulting in strange behaviours (container
programs cannot signal each other, or host processes like containerd
cannot signal containers).

The reason this happens only on some distributions (and is not a kernel
regression) is that the kernel doesn't enforce signal mediation unless
the profile contains signal rules. However because our profies #include
the distribution-managed <abstractions/base>, some distributions added
signal rules -- which results in AppArmor enforcing signal mediation and
thus a regression. On these systems, containers cannot send and receive
signals at all -- meaning they cannot signal each other and the
container runtime cannot kill them either.

This issue was fixed in Docker in 2018[1] but this code was copied
before then and thus the patches weren't carried. It also contains a new
fix for a more esoteric case[2]. Ideally this code should live in a
project like "containerd/apparmor" so that Docker, libpod, and
containerd can share it, but that's probably something to do separately.

In addition, the copyright header is updated to reference that the code
is copied from Docker (and thus was not written entirely by the
containerd authors).

[1]: moby/moby#37831
[2]: moby/moby#41337

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
(cherry picked from commit d8572b6)
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
brandond pushed a commit to brandond/containerd that referenced this pull request Jul 19, 2021
On newer kernels and systems, AppArmor will block sending signals in
many scenarios by default resulting in strange behaviours (container
programs cannot signal each other, or host processes like containerd
cannot signal containers).

The reason this happens only on some distributions (and is not a kernel
regression) is that the kernel doesn't enforce signal mediation unless
the profile contains signal rules. However because our profies #include
the distribution-managed <abstractions/base>, some distributions added
signal rules -- which results in AppArmor enforcing signal mediation and
thus a regression. On these systems, containers cannot send and receive
signals at all -- meaning they cannot signal each other and the
container runtime cannot kill them either.

This issue was fixed in Docker in 2018[1] but this code was copied
before then and thus the patches weren't carried. It also contains a new
fix for a more esoteric case[2]. Ideally this code should live in a
project like "containerd/apparmor" so that Docker, libpod, and
containerd can share it, but that's probably something to do separately.

In addition, the copyright header is updated to reference that the code
is copied from Docker (and thus was not written entirely by the
containerd authors).

[1]: moby/moby#37831
[2]: moby/moby#41337

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
(cherry picked from commit d8572b6)
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
brandond pushed a commit to brandond/containerd that referenced this pull request Jul 20, 2021
On newer kernels and systems, AppArmor will block sending signals in
many scenarios by default resulting in strange behaviours (container
programs cannot signal each other, or host processes like containerd
cannot signal containers).

The reason this happens only on some distributions (and is not a kernel
regression) is that the kernel doesn't enforce signal mediation unless
the profile contains signal rules. However because our profies #include
the distribution-managed <abstractions/base>, some distributions added
signal rules -- which results in AppArmor enforcing signal mediation and
thus a regression. On these systems, containers cannot send and receive
signals at all -- meaning they cannot signal each other and the
container runtime cannot kill them either.

This issue was fixed in Docker in 2018[1] but this code was copied
before then and thus the patches weren't carried. It also contains a new
fix for a more esoteric case[2]. Ideally this code should live in a
project like "containerd/apparmor" so that Docker, libpod, and
containerd can share it, but that's probably something to do separately.

In addition, the copyright header is updated to reference that the code
is copied from Docker (and thus was not written entirely by the
containerd authors).

[1]: moby/moby#37831
[2]: moby/moby#41337

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
(cherry picked from commit d8572b6)
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
brandond pushed a commit to brandond/containerd that referenced this pull request Aug 13, 2021
On newer kernels and systems, AppArmor will block sending signals in
many scenarios by default resulting in strange behaviours (container
programs cannot signal each other, or host processes like containerd
cannot signal containers).

The reason this happens only on some distributions (and is not a kernel
regression) is that the kernel doesn't enforce signal mediation unless
the profile contains signal rules. However because our profies #include
the distribution-managed <abstractions/base>, some distributions added
signal rules -- which results in AppArmor enforcing signal mediation and
thus a regression. On these systems, containers cannot send and receive
signals at all -- meaning they cannot signal each other and the
container runtime cannot kill them either.

This issue was fixed in Docker in 2018[1] but this code was copied
before then and thus the patches weren't carried. It also contains a new
fix for a more esoteric case[2]. Ideally this code should live in a
project like "containerd/apparmor" so that Docker, libpod, and
containerd can share it, but that's probably something to do separately.

In addition, the copyright header is updated to reference that the code
is copied from Docker (and thus was not written entirely by the
containerd authors).

[1]: moby/moby#37831
[2]: moby/moby#41337

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
(cherry picked from commit d8572b6)
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
brandond pushed a commit to k3s-io/containerd that referenced this pull request Oct 4, 2021
On newer kernels and systems, AppArmor will block sending signals in
many scenarios by default resulting in strange behaviours (container
programs cannot signal each other, or host processes like containerd
cannot signal containers).

The reason this happens only on some distributions (and is not a kernel
regression) is that the kernel doesn't enforce signal mediation unless
the profile contains signal rules. However because our profies #include
the distribution-managed <abstractions/base>, some distributions added
signal rules -- which results in AppArmor enforcing signal mediation and
thus a regression. On these systems, containers cannot send and receive
signals at all -- meaning they cannot signal each other and the
container runtime cannot kill them either.

This issue was fixed in Docker in 2018[1] but this code was copied
before then and thus the patches weren't carried. It also contains a new
fix for a more esoteric case[2]. Ideally this code should live in a
project like "containerd/apparmor" so that Docker, libpod, and
containerd can share it, but that's probably something to do separately.

In addition, the copyright header is updated to reference that the code
is copied from Docker (and thus was not written entirely by the
containerd authors).

[1]: moby/moby#37831
[2]: moby/moby#41337

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
(cherry picked from commit d8572b6)
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
brandond pushed a commit to brandond/containerd that referenced this pull request Nov 18, 2021
On newer kernels and systems, AppArmor will block sending signals in
many scenarios by default resulting in strange behaviours (container
programs cannot signal each other, or host processes like containerd
cannot signal containers).

The reason this happens only on some distributions (and is not a kernel
regression) is that the kernel doesn't enforce signal mediation unless
the profile contains signal rules. However because our profies #include
the distribution-managed <abstractions/base>, some distributions added
signal rules -- which results in AppArmor enforcing signal mediation and
thus a regression. On these systems, containers cannot send and receive
signals at all -- meaning they cannot signal each other and the
container runtime cannot kill them either.

This issue was fixed in Docker in 2018[1] but this code was copied
before then and thus the patches weren't carried. It also contains a new
fix for a more esoteric case[2]. Ideally this code should live in a
project like "containerd/apparmor" so that Docker, libpod, and
containerd can share it, but that's probably something to do separately.

In addition, the copyright header is updated to reference that the code
is copied from Docker (and thus was not written entirely by the
containerd authors).

[1]: moby/moby#37831
[2]: moby/moby#41337

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
(cherry picked from commit d8572b6)
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants