mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-04-09 18:45:54 +02:00
Updated kernel (2.6.27.41).
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Linux kernel version: 2.6.27.39
|
||||
# Tue Nov 17 16:59:43 2009
|
||||
# Linux kernel version: 2.6.27.41
|
||||
# Thu Dec 10 21:31:08 2009
|
||||
#
|
||||
# CONFIG_64BIT is not set
|
||||
CONFIG_X86_32=y
|
||||
@@ -450,7 +450,7 @@ CONFIG_NETFILTER_NETLINK=m
|
||||
CONFIG_NETFILTER_NETLINK_QUEUE=m
|
||||
CONFIG_NETFILTER_NETLINK_LOG=m
|
||||
CONFIG_NF_CONNTRACK=m
|
||||
CONFIG_NF_CT_ACCT=y
|
||||
CONFIG_NF_CONNTRACK_ACCT=y
|
||||
CONFIG_NF_CONNTRACK_MARK=y
|
||||
CONFIG_NF_CONNTRACK_EVENTS=y
|
||||
CONFIG_NF_CT_PROTO_DCCP=m
|
||||
@@ -505,8 +505,6 @@ CONFIG_NETFILTER_XT_MATCH_RATEEST=m
|
||||
CONFIG_NETFILTER_XT_MATCH_REALM=m
|
||||
CONFIG_NETFILTER_XT_MATCH_SCTP=m
|
||||
CONFIG_NETFILTER_XT_MATCH_STATE=m
|
||||
CONFIG_NETFILTER_XT_MATCH_LAYER7=m
|
||||
# CONFIG_NETFILTER_XT_MATCH_LAYER7_DEBUG is not set
|
||||
CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
|
||||
CONFIG_NETFILTER_XT_MATCH_STRING=m
|
||||
CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
. /opt/pakfire/lib/functions.sh
|
||||
/usr/local/bin/backupctrl exclude >/dev/null 2>&1
|
||||
#
|
||||
KVER="2.6.27.39"
|
||||
KVER="2.6.27.41"
|
||||
ROOT=`grep "root=" /boot/grub/grub.conf | cut -d"=" -f2 | cut -d" " -f1 | tail -n 1`
|
||||
MOUNT=`grep "kernel" /boot/grub/grub.conf | tail -n 1`
|
||||
# Nur den letzten Parameter verwenden
|
||||
|
||||
@@ -36,17 +36,15 @@
|
||||
* Unix-Syslog-0.100
|
||||
* XML-Parser-2.34
|
||||
* alsa-lib-1.0.21a
|
||||
* alsa-lib-1.0.21a-kmod-2.6.27.39-ipfire
|
||||
* alsa-lib-1.0.21a-kmod-2.6.27.41-ipfire
|
||||
* amavisd-new-2.5.2
|
||||
* apcupsd-3.14.4
|
||||
* applejuice-0.31
|
||||
* arping-2.05
|
||||
* as86-0.16.17
|
||||
* asterisk-1.4.18
|
||||
* atl1c-kmod-2.6.27.39-ipfire
|
||||
* atl1c-kmod-2.6.27.39-ipfire-xen
|
||||
* atl2-2.0.5-kmod-2.6.27.39-ipfire
|
||||
* atl2-2.0.5-kmod-2.6.27.39-ipfire-xen
|
||||
* atl1c-kmod-2.6.27.41-ipfire
|
||||
* atl2-2.0.5-kmod-2.6.27.41-ipfire
|
||||
* autoconf-2.59
|
||||
* automake-1.9.6
|
||||
* backup-ipfire
|
||||
@@ -71,8 +69,7 @@
|
||||
* clamav-0.95.3
|
||||
* cmake-2.4.8
|
||||
* collectd-4.5.3
|
||||
* compat-wireless-2.6.32-rc7-kmod-2.6.27.39-ipfire
|
||||
* compat-wireless-2.6.32-rc7-kmod-2.6.27.39-ipfire-xen
|
||||
* compat-wireless-2.6.32-rc7-kmod-2.6.27.41-ipfire
|
||||
* coreutils-5.96
|
||||
* cpio-2.6
|
||||
* cpufrequtils-005
|
||||
@@ -87,8 +84,7 @@
|
||||
* diffutils-2.8.1
|
||||
* dnsmasq-2.45
|
||||
* dosfstools-2.11
|
||||
* e1000e-1.0.2.5-kmod-2.6.27.39-ipfire
|
||||
* e1000e-1.0.2.5-kmod-2.6.27.39-ipfire-xen
|
||||
* e1000e-1.0.2.5-kmod-2.6.27.41-ipfire
|
||||
* e2fsprogs-1.39
|
||||
* ebtables-v2.0.8-2
|
||||
* ed-0.2
|
||||
@@ -134,8 +130,7 @@
|
||||
* hdparm-8.9
|
||||
* hostapd-0.6.9
|
||||
* hplip-2.7.10
|
||||
* hso-1.9-kmod-2.6.27.39-ipfire
|
||||
* hso-1.9-kmod-2.6.27.39-ipfire-xen
|
||||
* hso-1.9-kmod-2.6.27.41-ipfire
|
||||
* htop-0.8.1
|
||||
* httpd-2.2.11
|
||||
* hwdata
|
||||
@@ -159,10 +154,9 @@
|
||||
* jpegsrc.v6b
|
||||
* kbd-1.12
|
||||
* klibc-1.5.14
|
||||
* kqemu-1.4.0pre1-kmod-2.6.27.39-ipfire
|
||||
* kqemu-1.4.0pre1-kmod-2.6.27.39-ipfire-xen
|
||||
* kqemu-1.4.0pre1-kmod-2.6.27.41-ipfire
|
||||
* kudzu-1.2.64
|
||||
* kvm-kmod-2.6.31.5-kmod-2.6.27.39-ipfire
|
||||
* kvm-kmod-2.6.31.5-kmod-2.6.27.41-ipfire
|
||||
* l7-protocols-2009-05-10
|
||||
* lame-3.97
|
||||
* lcd4linux-0.10.1-RC2
|
||||
@@ -192,8 +186,7 @@
|
||||
* libwww-perl-5.803
|
||||
* libxml2-2.6.26
|
||||
* libxslt-1.1.17
|
||||
* linux-2.6.27.39-ipfire
|
||||
* linux-2.6.27.39-ipfire-xen
|
||||
* linux-2.6.27.41-ipfire
|
||||
* linux-atm-2.4.1
|
||||
* linux-libc-headers-2.6.12.0
|
||||
* lm_sensors-3.0.3
|
||||
@@ -203,11 +196,9 @@
|
||||
* lynis-1.2.6
|
||||
* lzo-2.02
|
||||
* m4-1.4.4
|
||||
* mISDN.git-9bf7deaa4b8829ab8fbccb34529a17aab2ddea93-kmod-2.6.27.39-ipfire
|
||||
* mISDN.git-9bf7deaa4b8829ab8fbccb34529a17aab2ddea93-kmod-2.6.27.39-ipfire-xen
|
||||
* mISDN.git-9bf7deaa4b8829ab8fbccb34529a17aab2ddea93-kmod-2.6.27.41-ipfire
|
||||
* mISDNuser.git-54928dec57bc846f2c2186f3640e69a053cd3641
|
||||
* madwifi-hal-0.10.5.6-r4031-20090529-kmod-2.6.27.39-ipfire
|
||||
* madwifi-hal-0.10.5.6-r4031-20090529-kmod-2.6.27.39-ipfire-xen
|
||||
* madwifi-hal-0.10.5.6-r4031-20090529-kmod-2.6.27.41-ipfire
|
||||
* make-3.81
|
||||
* man-db-2.4.3
|
||||
* man-pages-2.34
|
||||
@@ -255,8 +246,7 @@
|
||||
* openssh-5.2p1
|
||||
* openssl-0.9.8k
|
||||
* openswan-2.6.23
|
||||
* openswan-2.6.23-kmod-2.6.27.39-ipfire
|
||||
* openswan-2.6.23-kmod-2.6.27.39-ipfire-xen
|
||||
* openswan-2.6.23-kmod-2.6.27.41-ipfire
|
||||
* openvpn-2.1_rc20
|
||||
* p7zip_4.65
|
||||
* pam_mysql-0.7RC1
|
||||
@@ -277,12 +267,9 @@
|
||||
* procps-3.2.6
|
||||
* psmisc-22.2
|
||||
* qemu-0.11.0
|
||||
* r8101-kmod-2.6.27.39-ipfire
|
||||
* r8101-kmod-2.6.27.39-ipfire-xen
|
||||
* r8168-8.014.00-kmod-2.6.27.39-ipfire
|
||||
* r8168-8.014.00-kmod-2.6.27.39-ipfire-xen
|
||||
* r8169-6.011.00-kmod-2.6.27.39-ipfire
|
||||
* r8169-6.011.00-kmod-2.6.27.39-ipfire-xen
|
||||
* r8101-kmod-2.6.27.41-ipfire
|
||||
* r8168-8.014.00-kmod-2.6.27.41-ipfire
|
||||
* r8169-6.011.00-kmod-2.6.27.41-ipfire
|
||||
* readline-5.1
|
||||
* reiser4progs-1.0.5
|
||||
* reiserfsprogs-3.6.19
|
||||
@@ -337,8 +324,7 @@
|
||||
* urlgrabber-3.1.0
|
||||
* usbutils-0.72
|
||||
* util-linux-2.12r
|
||||
* v4l-dvb-aba823ecaea6-kmod-2.6.27.39-ipfire
|
||||
* v4l-dvb-aba823ecaea6-kmod-2.6.27.39-ipfire-xen
|
||||
* v4l-dvb-aba823ecaea6-kmod-2.6.27.41-ipfire
|
||||
* vdr-1.6.0
|
||||
* vdradmin-am-3.6.4
|
||||
* vim-7.0
|
||||
|
||||
22
lfs/linux
22
lfs/linux
@@ -24,8 +24,8 @@
|
||||
|
||||
include Config
|
||||
|
||||
PATCHLEVEL = .39
|
||||
VER = 2.6.27.39
|
||||
PATCHLEVEL = .41
|
||||
VER = 2.6.27.41
|
||||
|
||||
THISAPP = linux-$(VER)
|
||||
DL_FILE = $(THISAPP).tar.bz2
|
||||
@@ -54,19 +54,23 @@ objects =$(DL_FILE) \
|
||||
squashfs3.4.tar.gz \
|
||||
netfilter-layer7-v2.21.tar.gz \
|
||||
patch-2.6.16-nath323-1.3.bz2 \
|
||||
reiser4-for-2.6.27.19.patch.bz2
|
||||
|
||||
reiser4-for-2.6.27.19.patch.bz2 \
|
||||
linux-$(VER)-suse_xen_patches.tar.bz2
|
||||
|
||||
$(DL_FILE) = $(URL_IPFIRE)/$(DL_FILE)
|
||||
netfilter-layer7-v2.21.tar.gz = $(URL_IPFIRE)/netfilter-layer7-v2.21.tar.gz
|
||||
patch-2.6.16-nath323-1.3.bz2 = $(URL_IPFIRE)/patch-2.6.16-nath323-1.3.bz2
|
||||
squashfs3.4.tar.gz = $(URL_IPFIRE)/squashfs3.4.tar.gz
|
||||
reiser4-for-2.6.27.19.patch.bz2 = $(URL_IPFIRE)/reiser4-for-2.6.27.19.patch.bz2
|
||||
linux-$(VER)-suse_xen_patches.tar.bz2 = $(URL_IPFIRE)/linux-$(VER)-suse_xen_patches.tar.bz2
|
||||
|
||||
$(DL_FILE)_MD5 = a1f935b170d9b63c0771a579b46c1123
|
||||
|
||||
$(DL_FILE)_MD5 = fa7de0ac40f11864f5d13f54a18fe9ad
|
||||
netfilter-layer7-v2.21.tar.gz_MD5 = 838422e7d9a06b42e682e9064e5210b5
|
||||
patch-2.6.16-nath323-1.3.bz2_MD5 = f926409ff703a307baf54b57ab75d138
|
||||
squashfs3.4.tar.gz_MD5 = 2a4d2995ad5aa6840c95a95ffa6b1da6
|
||||
reiser4-for-2.6.27.19.patch.bz2_MD5 = 22988387f64f299489b90b484b2642cc
|
||||
linux-$(VER)-suse_xen_patches.tar.bz2_MD5 = 0d7d03f04ebfc22881a7c24ef5f1b7f5
|
||||
|
||||
install : $(TARGET)
|
||||
|
||||
@@ -97,15 +101,17 @@ $(subst %,%_MD5,$(objects)) :
|
||||
|
||||
$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
|
||||
@$(PREBUILD)
|
||||
@rm -rf $(DIR_APP) $(DIR_SRC)/linux $(DIR_SRC)/xen-* && cd $(DIR_SRC) && tar jxf $(DIR_DL)/$(DL_FILE)
|
||||
@rm -rf $(DIR_APP) $(DIR_SRC)/linux $(DIR_SRC)/linux-*-suse_xen_patches $(DIR_SRC)/xen-* && cd $(DIR_SRC) && tar jxf $(DIR_DL)/$(DL_FILE)
|
||||
ln -s linux-$(VER) /usr/src/linux
|
||||
|
||||
ifeq "$(XEN)" "1"
|
||||
# Apply Xen patches (provided by SuSE)
|
||||
cd $(DIR_SRC)/src/patches/suse-$(VER) && \
|
||||
for x in $$( $(DIR_SRC)/src/patches/suse-$(VER)/guards $$( $(DIR_SRC)/src/patches/suse-$(VER)/arch-symbols) < $(DIR_SRC)/src/patches/suse-$(VER)/series.conf); do \
|
||||
cd $(DIR_SRC) && tar jxf $(DIR_DL)/linux-$(VER)-suse_xen_patches.tar.bz2
|
||||
cd $(DIR_SRC)/linux-$(VER)-suse_xen_patches && \
|
||||
for x in $$( ./guards $$( ./arch-symbols) < ./series.conf); do \
|
||||
patch -d $(DIR_APP) -p1 < $$x || break; \
|
||||
done
|
||||
rm -rf $(DIR_SRC)/linux-*-suse_xen_patches
|
||||
|
||||
# Linux Intermediate Queueing Device
|
||||
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/imq-skbuff.patch
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
. /opt/pakfire/lib/functions.sh
|
||||
extract_files
|
||||
#
|
||||
KVER=2.6.27.39
|
||||
KVER=2.6.27.41
|
||||
ROOT=`grep "root=" /boot/grub/grub.conf | cut -d"=" -f2 | cut -d" " -f1 | tail -n 1`
|
||||
MOUNT=`grep "kernel" /boot/grub/grub.conf | tail -n 1`
|
||||
# Nur den letzten Parameter verwenden
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Generate architecture specific patch selection symbols
|
||||
|
||||
if [ "$1" = "--list" ]; then
|
||||
# List all known architectures
|
||||
echo i386 mips{,64} sparc{,64} ppc{,64} s390{,x} ia64 x86_64 alpha parisc
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$SYMBOLS" ]; then
|
||||
if [ -n "$1" ]; then
|
||||
ARCH="$1"
|
||||
elif [ -n "$PATCH_ARCH" ]; then
|
||||
ARCH="$PATCH_ARCH"
|
||||
else
|
||||
ARCH="`arch`"
|
||||
fi
|
||||
SYMBOLS="$ARCH"
|
||||
case "$ARCH" in
|
||||
(i?86) SYMBOLS="$SYMBOLS IA32" ;;
|
||||
(mips*) SYMBOLS="$SYMBOLS MIPS" ;;
|
||||
(sparc*) SYMBOLS="$SYMBOLS SPARC" ;;
|
||||
(ppc*) SYMBOLS="$SYMBOLS PPC" ;;
|
||||
(s390*) SYMBOLS="$SYMBOLS S390" ;;
|
||||
(ia64) ;;
|
||||
(x86_64) ;;
|
||||
(alpha) ;;
|
||||
(parisc) ;;
|
||||
(*) # not a recognized architeture!
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
echo $SYMBOLS
|
||||
@@ -1,287 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
#
|
||||
# Guards:
|
||||
#
|
||||
# +xxx include if xxx is defined
|
||||
# -xxx exclude if xxx is defined
|
||||
# +!xxx include if xxx is not defined
|
||||
# -!xxx exclude if xxx is not defined
|
||||
#
|
||||
|
||||
use FileHandle;
|
||||
use Getopt::Long;
|
||||
use strict;
|
||||
|
||||
# Prototypes
|
||||
sub files_in($$);
|
||||
sub parse($$);
|
||||
sub help();
|
||||
|
||||
#sub strip_ext($) {
|
||||
# local ($_) = @_;
|
||||
# s/\.(diff?|patch)$//;
|
||||
#}
|
||||
|
||||
#sub try_ext($) {
|
||||
# my ($path) = @_;
|
||||
# for my $p in (($path, "$path.diff", "$path.dif", "$path.patch")) {
|
||||
# return $p
|
||||
# if (-f $p);
|
||||
# }
|
||||
# return undef;
|
||||
#}
|
||||
|
||||
sub slashme($) {
|
||||
my ($dir) = @_;
|
||||
$dir =~ s#([^/])$#$&/#; # append a slash if necessary
|
||||
if ($dir eq './') {
|
||||
return '';
|
||||
} else {
|
||||
return $dir;
|
||||
}
|
||||
}
|
||||
|
||||
# Generate a list of files in a directory
|
||||
#
|
||||
sub files_in($$) {
|
||||
my ($dir, $path) = @_;
|
||||
my $dh = new FileHandle;
|
||||
my (@files, $file);
|
||||
|
||||
|
||||
opendir $dh, length("$dir$path") ? "$dir$path" : '.'
|
||||
or die "$dir$path: $!\n";
|
||||
while ($file = readdir($dh)) {
|
||||
next if $file =~ /^(\.|\.\.|\.#.*|CVS|.*~)$/;
|
||||
if (-d "$dir$path$file") {
|
||||
@files = (@files, files_in($dir, "$path$file/"));
|
||||
} else {
|
||||
#print "[$path$file]\n";
|
||||
push @files, "$path$file";
|
||||
}
|
||||
}
|
||||
closedir $dh;
|
||||
return @files;
|
||||
}
|
||||
|
||||
# Parse a configuration file
|
||||
# Callback called with ($patch, @guards) arguments
|
||||
#
|
||||
sub parse($$) {
|
||||
my ($fh, $callback) = @_;
|
||||
|
||||
my $line = "";
|
||||
|
||||
while (<$fh>) {
|
||||
chomp;
|
||||
s/(^|\s+)#.*//;
|
||||
if (s/\\$/ /) {
|
||||
$line .= $_;
|
||||
next;
|
||||
}
|
||||
$line .= $_;
|
||||
my @guards = ();
|
||||
foreach my $token (split /[\s\t\n]+/, $line) {
|
||||
next if $token eq "";
|
||||
if ($token =~ /^[-+]/) {
|
||||
push @guards, $token;
|
||||
} else {
|
||||
#print "[" . join(",", @guards) . "] $token\n";
|
||||
&$callback($token, @guards);
|
||||
}
|
||||
}
|
||||
$line = "";
|
||||
}
|
||||
}
|
||||
|
||||
# Command line options
|
||||
#
|
||||
my ($dir, $config, $default, $check, $list, $invert_match, $with_guards) =
|
||||
( '', '-', 1, 0, 0, 0, 0);
|
||||
my @path;
|
||||
|
||||
# Help text
|
||||
#
|
||||
sub help() {
|
||||
print "$0 - select from a list of files guarded by conditions\n";
|
||||
print "SYNOPSIS: $0 [--prefix=dir] [--path=dir1:dir2:...]\n" .
|
||||
" [--default=0|1] [--check|--list] [--invert-match]\n" .
|
||||
" [--with-guards] [--config=file] symbol ...\n\n" .
|
||||
" (Default values: --path='" . join(':', @path) . "', " .
|
||||
"--default=$default)\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# Parse command line options
|
||||
#
|
||||
Getopt::Long::Configure ("bundling");
|
||||
eval {
|
||||
unless (GetOptions (
|
||||
'd|prefix=s' => \$dir,
|
||||
'c|config=s' => \$config,
|
||||
'C|check' => \$check,
|
||||
'l|list' => \$list,
|
||||
'w|with-guards' => \$with_guards,
|
||||
'p|path=s' => \@path,
|
||||
'D|default=i' => \$default,
|
||||
'v|invert-match' => \$invert_match,
|
||||
'h|help' => sub { help(); exit 0; })) {
|
||||
help();
|
||||
exit 1;
|
||||
}
|
||||
};
|
||||
if ($@) {
|
||||
print "$@";
|
||||
help();
|
||||
exit 1;
|
||||
}
|
||||
|
||||
@path = ('.')
|
||||
unless (@path);
|
||||
@path = split(/:/, join(':', @path));
|
||||
|
||||
my $fh = ($config eq '-') ? \*STDIN : new FileHandle($config)
|
||||
or die "$config: $!\n";
|
||||
|
||||
$dir = slashme($dir);
|
||||
|
||||
if ($check) {
|
||||
# Check for duplicate files, or for files that are not referenced by
|
||||
# the specification.
|
||||
|
||||
my $problems = 0;
|
||||
my @files;
|
||||
|
||||
foreach (@path) {
|
||||
@files = (@files, files_in($dir, slashme($_)));
|
||||
}
|
||||
my %files = map { $_ => 0 } @files;
|
||||
|
||||
parse($fh, sub {
|
||||
my ($patch, @guards) = @_;
|
||||
if (exists $files{$patch}) {
|
||||
$files{$patch}++;
|
||||
} else {
|
||||
print "Not found: $dir$patch\n";
|
||||
$problems++;
|
||||
}});
|
||||
|
||||
$fh->close();
|
||||
|
||||
my ($file, $ref);
|
||||
while (($file, $ref) = each %files) {
|
||||
next if $ref == 1;
|
||||
|
||||
if ($ref == 0) {
|
||||
print "Unused: $file\n" if $ref == 0;
|
||||
$problems++;
|
||||
}
|
||||
if ($ref > 1) {
|
||||
print "Warning: multiple uses: $file\n" if $ref > 1;
|
||||
# This is not an error if the entries are mutually exclusive...
|
||||
}
|
||||
}
|
||||
exit $problems ? 1 : 0;
|
||||
|
||||
} elsif ($list) {
|
||||
parse($fh, sub {
|
||||
my ($patch, @guards) = @_;
|
||||
print join(' ', @guards), ' '
|
||||
if (@guards && $with_guards);
|
||||
print "$dir$patch\n";
|
||||
});
|
||||
} else {
|
||||
# Generate a list of patches to apply.
|
||||
|
||||
my %symbols = map { $_ => 1 } @ARGV;
|
||||
|
||||
parse($fh, sub {
|
||||
my ($patch, @guards) = @_;
|
||||
|
||||
my $selected;
|
||||
if (@guards) {
|
||||
# If the first guard is -xxx, the patch is included by default;
|
||||
# if it is +xxx, the patch is excluded by default.
|
||||
$selected = ($guards[0] =~ /^-/);
|
||||
|
||||
foreach (@guards) {
|
||||
/^([-+])(!?)(.*)?/
|
||||
or die "Bad guard '$_'\n";
|
||||
|
||||
# Check if the guard matches
|
||||
if (($2 eq '!' && !exists $symbols{$3}) ||
|
||||
($2 eq '' && ( $3 eq '' || exists $symbols{$3}))) {
|
||||
# Include or exclude
|
||||
$selected = ($1 eq '+');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# If there are no guards, use the specified default result.
|
||||
$selected = $default;
|
||||
}
|
||||
|
||||
print "$dir$patch\n"
|
||||
if $selected ^ $invert_match;
|
||||
});
|
||||
|
||||
$fh->close();
|
||||
|
||||
exit 0;
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
guards - select from a list of files guarded by conditions
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
F<guards> [--prefix=F<dir>] [--path=F<dir1:dir2:...>] [--default=<0|1>]
|
||||
[--check|--list] [--invert-match] [--with-guards] [--config=<file>]
|
||||
I<symbol> ...
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The script reads a configuration file that may contain so-called guards, file
|
||||
names, and comments, and writes those file names that satisfy all guards to
|
||||
standard output. The script takes a list of symbols as its arguments. Each line
|
||||
in the configuration file is processed separately. Lines may start with a
|
||||
number of guards. The following guards are defined:
|
||||
|
||||
=over
|
||||
|
||||
+I<xxx> Include the file(s) on this line if the symbol I<xxx> is defined.
|
||||
|
||||
-I<xxx> Exclude the file(s) on this line if the symbol I<xxx> is defined.
|
||||
|
||||
+!I<xxx> Include the file(s) on this line if the symbol I<xxx> is not defined.
|
||||
|
||||
-!I<xxx> Exclude the file(s) on this line if the symbol I<xxx> is not defined.
|
||||
|
||||
- Exclude this file. Used to avoid spurious I<--check> messages.
|
||||
|
||||
=back
|
||||
|
||||
The guards are processed left to right. The last guard that matches determines
|
||||
if the file is included. If no guard is specified, the I<--default>
|
||||
setting determines if the file is included.
|
||||
|
||||
If no configuration file is specified, the script reads from standard input.
|
||||
|
||||
The I<--check> option is used to compare the specification file against the
|
||||
file system. If files are referenced in the specification that do not exist, or
|
||||
if files are not enlisted in the specification file warnings are printed. The
|
||||
I<--path> option can be used to specify which directory or directories to scan.
|
||||
Multiple directories are eparated by a colon (C<:>) character. The
|
||||
I<--prefix> option specifies the location of the files.
|
||||
|
||||
Use I<--list> to list all files independend of any rules. Use I<--invert-match>
|
||||
to list only the excluded patches. Use I<--with-guards> to also include all
|
||||
inclusion and exclusion rules.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Andreas Gruenbacher <agruen@suse.de>, SUSE Labs
|
||||
@@ -1,201 +0,0 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: [PATCH] vfs: introduce path_permission()
|
||||
|
||||
2.6.27 eliminated the nameidata parameter from permission and replaced
|
||||
several call sites with inode_permission. This keeps the information
|
||||
required by AppArmor from reaching it.
|
||||
|
||||
The following patch factors out the permission assessment part of
|
||||
inode_permission into __inode_permission and adds a path_permission
|
||||
function that takes a struct path instead of a struct inode and passes
|
||||
it to security_path_permission instead of security_inode_permission.
|
||||
|
||||
All of the call sites that had access to a struct path whether by
|
||||
itself or via a file or nameidata (and used it) in 2.6.26 are changed
|
||||
to use the path_permission call.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
fs/inotify_user.c | 2 +-
|
||||
fs/namei.c | 32 ++++++++++++++++++++++++--------
|
||||
fs/open.c | 10 +++++-----
|
||||
include/linux/fs.h | 5 +++++
|
||||
4 files changed, 35 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/fs/inotify_user.c
|
||||
+++ b/fs/inotify_user.c
|
||||
@@ -372,7 +372,7 @@ static int find_inode(const char __user
|
||||
if (error)
|
||||
return error;
|
||||
/* you can only watch an inode if you have read permissions on it */
|
||||
- error = inode_permission(path->dentry->d_inode, MAY_READ);
|
||||
+ error = path_permission(path, MAY_READ);
|
||||
if (error)
|
||||
path_put(path);
|
||||
return error;
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -227,7 +227,7 @@ int generic_permission(struct inode *ino
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
-int inode_permission(struct inode *inode, int mask)
|
||||
+static int __inode_permission(struct inode *inode, int mask)
|
||||
{
|
||||
int retval;
|
||||
int submask = mask;
|
||||
@@ -273,7 +273,12 @@ int inode_permission(struct inode *inode
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
- retval = devcgroup_inode_permission(inode, mask);
|
||||
+ return devcgroup_inode_permission(inode, mask);
|
||||
+}
|
||||
+
|
||||
+int inode_permission(struct inode *inode, int mask)
|
||||
+{
|
||||
+ int retval = __inode_permission(inode, mask);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
@@ -281,6 +286,15 @@ int inode_permission(struct inode *inode
|
||||
mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
|
||||
}
|
||||
|
||||
+int path_permission(struct path *path, int mask)
|
||||
+{
|
||||
+ int retval = __inode_permission(path->dentry->d_inode, mask);
|
||||
+ if (retval)
|
||||
+ return retval;
|
||||
+ return security_path_permission(path,
|
||||
+ mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* vfs_permission - check for access rights to a given path
|
||||
* @nd: lookup result that describes the path
|
||||
@@ -293,7 +307,7 @@ int inode_permission(struct inode *inode
|
||||
*/
|
||||
int vfs_permission(struct nameidata *nd, int mask)
|
||||
{
|
||||
- return inode_permission(nd->path.dentry->d_inode, mask);
|
||||
+ return path_permission(&nd->path, mask);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,7 +324,7 @@ int vfs_permission(struct nameidata *nd,
|
||||
*/
|
||||
int file_permission(struct file *file, int mask)
|
||||
{
|
||||
- return inode_permission(file->f_path.dentry->d_inode, mask);
|
||||
+ return path_permission(&file->f_path, mask);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -452,8 +466,9 @@ static struct dentry * cached_lookup(str
|
||||
* short-cut DAC fails, then call permission() to do more
|
||||
* complete permission check.
|
||||
*/
|
||||
-static int exec_permission_lite(struct inode *inode)
|
||||
+static int exec_permission_lite(struct path *path)
|
||||
{
|
||||
+ struct inode *inode = path->dentry->d_inode;
|
||||
umode_t mode = inode->i_mode;
|
||||
|
||||
if (inode->i_op && inode->i_op->permission)
|
||||
@@ -478,7 +493,7 @@ static int exec_permission_lite(struct i
|
||||
|
||||
return -EACCES;
|
||||
ok:
|
||||
- return security_inode_permission(inode, MAY_EXEC);
|
||||
+ return security_path_permission(path, MAY_EXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -875,7 +890,7 @@ static int __link_path_walk(const char *
|
||||
unsigned int c;
|
||||
|
||||
nd->flags |= LOOKUP_CONTINUE;
|
||||
- err = exec_permission_lite(inode);
|
||||
+ err = exec_permission_lite(&nd->path);
|
||||
if (err == -EAGAIN)
|
||||
err = vfs_permission(nd, MAY_EXEC);
|
||||
if (err)
|
||||
@@ -1250,7 +1265,7 @@ static struct dentry *lookup_hash(struct
|
||||
{
|
||||
int err;
|
||||
|
||||
- err = inode_permission(nd->path.dentry->d_inode, MAY_EXEC);
|
||||
+ err = path_permission(&nd->path, MAY_EXEC);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return __lookup_hash(&nd->last, nd->path.dentry, nd);
|
||||
@@ -2907,6 +2922,7 @@ EXPORT_SYMBOL(page_symlink_inode_operati
|
||||
EXPORT_SYMBOL(path_lookup);
|
||||
EXPORT_SYMBOL(vfs_path_lookup);
|
||||
EXPORT_SYMBOL(inode_permission);
|
||||
+EXPORT_SYMBOL(path_permission);
|
||||
EXPORT_SYMBOL(vfs_permission);
|
||||
EXPORT_SYMBOL(file_permission);
|
||||
EXPORT_SYMBOL(unlock_rename);
|
||||
--- a/fs/open.c
|
||||
+++ b/fs/open.c
|
||||
@@ -248,7 +248,7 @@ static long do_sys_truncate(const char _
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
- error = inode_permission(inode, MAY_WRITE);
|
||||
+ error = path_permission(&path, MAY_WRITE);
|
||||
if (error)
|
||||
goto mnt_drop_write_and_out;
|
||||
|
||||
@@ -493,7 +493,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, con
|
||||
goto out_path_release;
|
||||
}
|
||||
|
||||
- res = inode_permission(inode, mode | MAY_ACCESS);
|
||||
+ res = path_permission(&path, mode | MAY_ACCESS);
|
||||
/* SuS v2 requires we report a read only fs too */
|
||||
if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
|
||||
goto out_path_release;
|
||||
@@ -536,7 +536,7 @@ SYSCALL_DEFINE1(chdir, const char __user
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
|
||||
+ error = path_permission(&path, MAY_EXEC | MAY_ACCESS);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
@@ -565,7 +565,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd
|
||||
if (!S_ISDIR(inode->i_mode))
|
||||
goto out_putf;
|
||||
|
||||
- error = inode_permission(inode, MAY_EXEC | MAY_ACCESS);
|
||||
+ error = path_permission(&file->f_path, MAY_EXEC | MAY_ACCESS);
|
||||
if (!error)
|
||||
set_fs_pwd(current->fs, &file->f_path);
|
||||
out_putf:
|
||||
@@ -583,7 +583,7 @@ SYSCALL_DEFINE1(chroot, const char __use
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
|
||||
+ error = path_permission(&path, MAY_EXEC | MAY_ACCESS);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1201,6 +1201,11 @@ extern void dentry_unhash(struct dentry
|
||||
extern int file_permission(struct file *, int);
|
||||
|
||||
/*
|
||||
+ * VFS path helper functions.
|
||||
+ */
|
||||
+extern int path_permission(struct path *, int);
|
||||
+
|
||||
+/*
|
||||
* File types
|
||||
*
|
||||
* NOTE! These match bits 12..15 of stat.st_mode
|
||||
@@ -1,109 +0,0 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: [PATCH] security: add ->path_permission
|
||||
|
||||
This patch adds a security_ops->path_permission hook that is identical to
|
||||
security_ops->inode_permission except that it is passed a struct path
|
||||
instead of a struct inode.
|
||||
|
||||
LSMs which don't implement it will have their ->inode_permission call
|
||||
used instead.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
|
||||
include/linux/security.h | 21 +++++++++++++++++++++
|
||||
security/capability.c | 6 ++++++
|
||||
security/security.c | 9 +++++++++
|
||||
3 files changed, 36 insertions(+)
|
||||
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -592,6 +592,20 @@ static inline void security_free_mnt_opt
|
||||
* file_permission, and recheck access if anything has changed
|
||||
* since inode_permission.
|
||||
*
|
||||
+ * Security hook for path
|
||||
+ *
|
||||
+ * @path_permission:
|
||||
+ * Check permission before accessing a path. This hook is called by the
|
||||
+ * existing Linux permission function, so a security module can use it to
|
||||
+ * provide additional checking for existing Linux permission checks.
|
||||
+ * Notice that this hook is called when a file is opened (as well as many
|
||||
+ * other operations), whereas the file_security_ops permission hook is
|
||||
+ * called when the actual read/write operations are performed. This
|
||||
+ * hook is optional and if absent, inode_permission will be substituted.
|
||||
+ * @path contains the path structure to check.
|
||||
+ * @mask contains the permission mask.
|
||||
+ * Return 0 if permission is granted.
|
||||
+
|
||||
* Security hooks for task operations.
|
||||
*
|
||||
* @task_create:
|
||||
@@ -1434,6 +1448,7 @@ struct security_operations {
|
||||
struct fown_struct *fown, int sig);
|
||||
int (*file_receive) (struct file *file);
|
||||
int (*dentry_open) (struct file *file);
|
||||
+ int (*path_permission) (struct path *path, int mask);
|
||||
|
||||
int (*task_create) (unsigned long clone_flags);
|
||||
int (*task_alloc_security) (struct task_struct *p);
|
||||
@@ -1708,6 +1723,7 @@ int security_file_send_sigiotask(struct
|
||||
struct fown_struct *fown, int sig);
|
||||
int security_file_receive(struct file *file);
|
||||
int security_dentry_open(struct file *file);
|
||||
+int security_path_permission(struct path *path, int mask);
|
||||
int security_task_create(unsigned long clone_flags);
|
||||
int security_task_alloc(struct task_struct *p);
|
||||
void security_task_free(struct task_struct *p);
|
||||
@@ -2242,6 +2258,11 @@ static inline int security_dentry_open(s
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+static inline int security_path_permission(struct path *path, int mask)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
static inline int security_task_create(unsigned long clone_flags)
|
||||
{
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -343,6 +343,11 @@ static int cap_dentry_open(struct file *
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int cap_path_permission(struct path *path, int mask)
|
||||
+{
|
||||
+ return security_inode_permission(path->dentry->d_inode, mask);
|
||||
+}
|
||||
+
|
||||
static int cap_task_create(unsigned long clone_flags)
|
||||
{
|
||||
return 0;
|
||||
@@ -897,6 +902,7 @@ void security_fixup_ops(struct security_
|
||||
set_to_cap_if_null(ops, file_send_sigiotask);
|
||||
set_to_cap_if_null(ops, file_receive);
|
||||
set_to_cap_if_null(ops, dentry_open);
|
||||
+ set_to_cap_if_null(ops, path_permission);
|
||||
set_to_cap_if_null(ops, task_create);
|
||||
set_to_cap_if_null(ops, task_alloc_security);
|
||||
set_to_cap_if_null(ops, task_free_security);
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -612,6 +612,15 @@ int security_dentry_open(struct file *fi
|
||||
return security_ops->dentry_open(file);
|
||||
}
|
||||
|
||||
+int security_path_permission(struct path *path, int mask)
|
||||
+{
|
||||
+ struct inode *inode = path->dentry->d_inode;
|
||||
+ if (unlikely(IS_PRIVATE(inode)))
|
||||
+ return 0;
|
||||
+
|
||||
+ return security_ops->path_permission(path, mask);
|
||||
+}
|
||||
+
|
||||
int security_task_create(unsigned long clone_flags)
|
||||
{
|
||||
return security_ops->task_create(clone_flags);
|
||||
@@ -1,47 +0,0 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: AppArmor: Patch AppArmor for 2.6.25 kernel
|
||||
|
||||
Add 64 bit capabilities support to AppArmor.
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/module_interface.c | 22 ++++++++++++++++++----
|
||||
1 file changed, 18 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/security/apparmor/module_interface.c
|
||||
+++ b/security/apparmor/module_interface.c
|
||||
@@ -395,15 +395,29 @@ static struct aa_profile *aa_unpack_prof
|
||||
if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
|
||||
goto fail;
|
||||
|
||||
- if (!aa_is_u32(e, &(profile->capabilities), NULL))
|
||||
+ if (!aa_is_u32(e, &(profile->capabilities.cap[0]), NULL))
|
||||
goto fail;
|
||||
- if (!aa_is_u32(e, &(profile->audit_caps), NULL))
|
||||
+ if (!aa_is_u32(e, &(profile->audit_caps.cap[0]), NULL))
|
||||
goto fail;
|
||||
- if (!aa_is_u32(e, &(profile->quiet_caps), NULL))
|
||||
+ if (!aa_is_u32(e, &(profile->quiet_caps.cap[0]), NULL))
|
||||
goto fail;
|
||||
- if (!aa_is_u32(e, &(profile->set_caps), NULL))
|
||||
+ if (!aa_is_u32(e, &(profile->set_caps.cap[0]), NULL))
|
||||
goto fail;
|
||||
|
||||
+ if (aa_is_nameX(e, AA_STRUCT, "caps64")) {
|
||||
+ /* optional upper half of 64 bit caps */
|
||||
+ if (!aa_is_u32(e, &(profile->capabilities.cap[1]), NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_u32(e, &(profile->audit_caps.cap[1]), NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_u32(e, &(profile->quiet_caps.cap[1]), NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_u32(e, &(profile->set_caps.cap[1]), NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
if (!aa_unpack_rlimits(e, profile))
|
||||
goto fail;
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Export audit subsystem for use by modules
|
||||
|
||||
Update kenel audit range comments to show AppArmor's registered range of
|
||||
1500-1599. This range used to be reserved for LSPP but LSPP uses the
|
||||
SE Linux range and the range was given to AppArmor.
|
||||
Adds necessary export symbols for audit subsystem routines.
|
||||
Changes audit_log_vformat to be externally visible (analagous to vprintf)
|
||||
Patch is not in mainline -- pending AppArmor code submission to lkml
|
||||
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
include/linux/audit.h | 12 +++++++++++-
|
||||
kernel/audit.c | 6 ++++--
|
||||
2 files changed, 15 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/include/linux/audit.h
|
||||
+++ b/include/linux/audit.h
|
||||
@@ -33,7 +33,7 @@
|
||||
* 1200 - 1299 messages internal to the audit daemon
|
||||
* 1300 - 1399 audit event messages
|
||||
* 1400 - 1499 SE Linux use
|
||||
- * 1500 - 1599 kernel LSPP events
|
||||
+ * 1500 - 1599 AppArmor use
|
||||
* 1600 - 1699 kernel crypto events
|
||||
* 1700 - 1799 kernel anomaly records
|
||||
* 1800 - 1999 future kernel use (maybe integrity labels and related events)
|
||||
@@ -119,6 +119,13 @@
|
||||
#define AUDIT_MAC_UNLBL_STCADD 1416 /* NetLabel: add a static label */
|
||||
#define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */
|
||||
|
||||
+#define AUDIT_APPARMOR_AUDIT 1501 /* AppArmor audited grants */
|
||||
+#define AUDIT_APPARMOR_ALLOWED 1502 /* Allowed Access for learning */
|
||||
+#define AUDIT_APPARMOR_DENIED 1503
|
||||
+#define AUDIT_APPARMOR_HINT 1504 /* Process Tracking information */
|
||||
+#define AUDIT_APPARMOR_STATUS 1505 /* Changes in config */
|
||||
+#define AUDIT_APPARMOR_ERROR 1506 /* Internal AppArmor Errors */
|
||||
+
|
||||
#define AUDIT_FIRST_KERN_ANOM_MSG 1700
|
||||
#define AUDIT_LAST_KERN_ANOM_MSG 1799
|
||||
#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
|
||||
@@ -545,6 +552,9 @@ extern void audit_log(struct audit_
|
||||
__attribute__((format(printf,4,5)));
|
||||
|
||||
extern struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type);
|
||||
+extern void audit_log_vformat(struct audit_buffer *ab,
|
||||
+ const char *fmt, va_list args)
|
||||
+ __attribute__((format(printf,2,0)));
|
||||
extern void audit_log_format(struct audit_buffer *ab,
|
||||
const char *fmt, ...)
|
||||
__attribute__((format(printf,2,3)));
|
||||
--- a/kernel/audit.c
|
||||
+++ b/kernel/audit.c
|
||||
@@ -1231,8 +1231,7 @@ static inline int audit_expand(struct au
|
||||
* will be called a second time. Currently, we assume that a printk
|
||||
* can't format message larger than 1024 bytes, so we don't either.
|
||||
*/
|
||||
-static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
|
||||
- va_list args)
|
||||
+void audit_log_vformat(struct audit_buffer *ab, const char *fmt, va_list args)
|
||||
{
|
||||
int len, avail;
|
||||
struct sk_buff *skb;
|
||||
@@ -1506,3 +1505,6 @@ EXPORT_SYMBOL(audit_log_start);
|
||||
EXPORT_SYMBOL(audit_log_end);
|
||||
EXPORT_SYMBOL(audit_log_format);
|
||||
EXPORT_SYMBOL(audit_log);
|
||||
+EXPORT_SYMBOL_GPL(audit_log_vformat);
|
||||
+EXPORT_SYMBOL_GPL(audit_log_untrustedstring);
|
||||
+EXPORT_SYMBOL_GPL(audit_log_d_path);
|
||||
@@ -1,31 +0,0 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: Add AppArmor LSM to security/Makefile
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
security/Kconfig | 1 +
|
||||
security/Makefile | 3 ++-
|
||||
2 files changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/security/Kconfig
|
||||
+++ b/security/Kconfig
|
||||
@@ -97,6 +97,7 @@ config SECURITY_ROOTPLUG
|
||||
|
||||
source security/selinux/Kconfig
|
||||
source security/smack/Kconfig
|
||||
+source security/apparmor/Kconfig
|
||||
|
||||
endmenu
|
||||
|
||||
--- a/security/Makefile
|
||||
+++ b/security/Makefile
|
||||
@@ -14,5 +14,6 @@ obj-$(CONFIG_SECURITY) += security.o c
|
||||
# Must precede capability.o in order to stack properly.
|
||||
obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
|
||||
obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
|
||||
-obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o
|
||||
+obj-$(CONFIG_SECURITY_APPARMOR) += commoncap.o apparmor/
|
||||
+ obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o
|
||||
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
|
||||
@@ -1,910 +0,0 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: AppArmor: Module and LSM hooks
|
||||
|
||||
Module parameters, LSM hooks, initialization and teardown.
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/lsm.c | 895 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 895 insertions(+)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -0,0 +1,895 @@
|
||||
+/*
|
||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ *
|
||||
+ * AppArmor LSM interface
|
||||
+ */
|
||||
+
|
||||
+#include <linux/security.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/mm.h>
|
||||
+#include <linux/mman.h>
|
||||
+#include <linux/mount.h>
|
||||
+#include <linux/namei.h>
|
||||
+#include <linux/ctype.h>
|
||||
+#include <linux/sysctl.h>
|
||||
+#include <linux/audit.h>
|
||||
+
|
||||
+#include "apparmor.h"
|
||||
+#include "inline.h"
|
||||
+
|
||||
+/* Flag indicating whether initialization completed */
|
||||
+int apparmor_initialized = 0;
|
||||
+
|
||||
+static int param_set_aabool(const char *val, struct kernel_param *kp);
|
||||
+static int param_get_aabool(char *buffer, struct kernel_param *kp);
|
||||
+#define param_check_aabool(name, p) __param_check(name, p, int)
|
||||
+
|
||||
+static int param_set_aauint(const char *val, struct kernel_param *kp);
|
||||
+static int param_get_aauint(char *buffer, struct kernel_param *kp);
|
||||
+#define param_check_aauint(name, p) __param_check(name, p, int)
|
||||
+
|
||||
+/* Flag values, also controllable via /sys/module/apparmor/parameters
|
||||
+ * We define special types as we want to do additional mediation.
|
||||
+ *
|
||||
+ * Complain mode -- in complain mode access failures result in auditing only
|
||||
+ * and task is allowed access. audit events are processed by userspace to
|
||||
+ * generate policy. Default is 'enforce' (0).
|
||||
+ * Value is also togglable per profile and referenced when global value is
|
||||
+ * enforce.
|
||||
+ */
|
||||
+int apparmor_complain = 0;
|
||||
+module_param_named(complain, apparmor_complain, aabool, S_IRUSR | S_IWUSR);
|
||||
+MODULE_PARM_DESC(apparmor_complain, "Toggle AppArmor complain mode");
|
||||
+
|
||||
+/* Debug mode */
|
||||
+int apparmor_debug = 0;
|
||||
+module_param_named(debug, apparmor_debug, aabool, S_IRUSR | S_IWUSR);
|
||||
+MODULE_PARM_DESC(apparmor_debug, "Toggle AppArmor debug mode");
|
||||
+
|
||||
+/* Audit mode */
|
||||
+int apparmor_audit = 0;
|
||||
+module_param_named(audit, apparmor_audit, aabool, S_IRUSR | S_IWUSR);
|
||||
+MODULE_PARM_DESC(apparmor_audit, "Toggle AppArmor audit mode");
|
||||
+
|
||||
+/* Syscall logging mode */
|
||||
+int apparmor_logsyscall = 0;
|
||||
+module_param_named(logsyscall, apparmor_logsyscall, aabool, S_IRUSR | S_IWUSR);
|
||||
+MODULE_PARM_DESC(apparmor_logsyscall, "Toggle AppArmor logsyscall mode");
|
||||
+
|
||||
+/* Maximum pathname length before accesses will start getting rejected */
|
||||
+unsigned int apparmor_path_max = 2 * PATH_MAX;
|
||||
+module_param_named(path_max, apparmor_path_max, aauint, S_IRUSR | S_IWUSR);
|
||||
+MODULE_PARM_DESC(apparmor_path_max, "Maximum pathname length allowed");
|
||||
+
|
||||
+/* Boot time disable flag */
|
||||
+#ifdef CONFIG_SECURITY_APPARMOR_DISABLE
|
||||
+#define AA_ENABLED_PERMS 0600
|
||||
+#else
|
||||
+#define AA_ENABLED_PERMS 0400
|
||||
+#endif
|
||||
+static int param_set_aa_enabled(const char *val, struct kernel_param *kp);
|
||||
+unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
|
||||
+module_param_call(enabled, param_set_aa_enabled, param_get_aauint,
|
||||
+ &apparmor_enabled, AA_ENABLED_PERMS);
|
||||
+MODULE_PARM_DESC(apparmor_enabled, "Enable/Disable Apparmor on boot");
|
||||
+
|
||||
+static int __init apparmor_enabled_setup(char *str)
|
||||
+{
|
||||
+ apparmor_enabled = simple_strtol(str, NULL, 0);
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("apparmor=", apparmor_enabled_setup);
|
||||
+
|
||||
+static int param_set_aabool(const char *val, struct kernel_param *kp)
|
||||
+{
|
||||
+ if (aa_task_context(current))
|
||||
+ return -EPERM;
|
||||
+ return param_set_bool(val, kp);
|
||||
+}
|
||||
+
|
||||
+static int param_get_aabool(char *buffer, struct kernel_param *kp)
|
||||
+{
|
||||
+ if (aa_task_context(current))
|
||||
+ return -EPERM;
|
||||
+ return param_get_bool(buffer, kp);
|
||||
+}
|
||||
+
|
||||
+static int param_set_aauint(const char *val, struct kernel_param *kp)
|
||||
+{
|
||||
+ if (aa_task_context(current))
|
||||
+ return -EPERM;
|
||||
+ return param_set_uint(val, kp);
|
||||
+}
|
||||
+
|
||||
+static int param_get_aauint(char *buffer, struct kernel_param *kp)
|
||||
+{
|
||||
+ if (aa_task_context(current))
|
||||
+ return -EPERM;
|
||||
+ return param_get_uint(buffer, kp);
|
||||
+}
|
||||
+
|
||||
+/* allow run time disabling of apparmor */
|
||||
+static int param_set_aa_enabled(const char *val, struct kernel_param *kp)
|
||||
+{
|
||||
+ char *endp;
|
||||
+ unsigned long l;
|
||||
+
|
||||
+ if (!apparmor_initialized) {
|
||||
+ apparmor_enabled = 0;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (aa_task_context(current))
|
||||
+ return -EPERM;
|
||||
+
|
||||
+ if (!apparmor_enabled)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!val)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ l = simple_strtoul(val, &endp, 0);
|
||||
+ if (endp == val || l != 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ apparmor_enabled = 0;
|
||||
+ apparmor_disable();
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aa_reject_syscall(struct task_struct *task, gfp_t flags,
|
||||
+ const char *name)
|
||||
+{
|
||||
+ struct aa_profile *profile = aa_get_profile(task);
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (profile) {
|
||||
+ error = aa_audit_syscallreject(profile, flags, name);
|
||||
+ aa_put_profile(profile);
|
||||
+ }
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_ptrace(struct task_struct *parent,
|
||||
+ struct task_struct *child, unsigned int mode)
|
||||
+{
|
||||
+ struct aa_task_context *cxt;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * parent can ptrace child when
|
||||
+ * - parent is unconfined
|
||||
+ * - parent & child are in the same namespace &&
|
||||
+ * - parent is in complain mode
|
||||
+ * - parent and child are confined by the same profile
|
||||
+ * - parent profile has CAP_SYS_PTRACE
|
||||
+ */
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ cxt = aa_task_context(parent);
|
||||
+ if (cxt) {
|
||||
+ if (parent->nsproxy != child->nsproxy) {
|
||||
+ struct aa_audit sa;
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = "ptrace";
|
||||
+ sa.gfp_mask = GFP_ATOMIC;
|
||||
+ sa.parent = parent->pid;
|
||||
+ sa.task = child->pid;
|
||||
+ sa.info = "different namespaces";
|
||||
+ aa_audit_reject(cxt->profile, &sa);
|
||||
+ error = -EPERM;
|
||||
+ } else {
|
||||
+ struct aa_task_context *child_cxt =
|
||||
+ aa_task_context(child);
|
||||
+
|
||||
+ error = aa_may_ptrace(cxt, child_cxt ?
|
||||
+ child_cxt->profile : NULL);
|
||||
+ if (PROFILE_COMPLAIN(cxt->profile)) {
|
||||
+ struct aa_audit sa;
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = "ptrace";
|
||||
+ sa.gfp_mask = GFP_ATOMIC;
|
||||
+ sa.parent = parent->pid;
|
||||
+ sa.task = child->pid;
|
||||
+ aa_audit_hint(cxt->profile, &sa);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_capable(struct task_struct *task, int cap)
|
||||
+{
|
||||
+ int error;
|
||||
+ struct aa_task_context *cxt;
|
||||
+
|
||||
+ /* cap_capable returns 0 on success, else -EPERM */
|
||||
+ error = cap_capable(task, cap);
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ cxt = aa_task_context(task);
|
||||
+ if (cxt && (!error || cap_raised(cxt->profile->set_caps, cap)))
|
||||
+ error = aa_capability(cxt, cap);
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_sysctl(struct ctl_table *table, int op)
|
||||
+{
|
||||
+ struct aa_profile *profile = aa_get_profile(current);
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (profile) {
|
||||
+ char *buffer, *name;
|
||||
+ int mask;
|
||||
+
|
||||
+ mask = 0;
|
||||
+ if (op & 4)
|
||||
+ mask |= MAY_READ;
|
||||
+ if (op & 2)
|
||||
+ mask |= MAY_WRITE;
|
||||
+
|
||||
+ error = -ENOMEM;
|
||||
+ buffer = (char*)__get_free_page(GFP_KERNEL);
|
||||
+ if (!buffer)
|
||||
+ goto out;
|
||||
+ name = sysctl_pathname(table, buffer, PAGE_SIZE);
|
||||
+ if (name && name - buffer >= 5) {
|
||||
+ name -= 5;
|
||||
+ memcpy(name, "/proc", 5);
|
||||
+ error = aa_perm_path(profile, "sysctl", name, mask, 0);
|
||||
+ }
|
||||
+ free_page((unsigned long)buffer);
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ aa_put_profile(profile);
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_bprm_set_security(struct linux_binprm *bprm)
|
||||
+{
|
||||
+ /* handle capability bits with setuid, etc */
|
||||
+ cap_bprm_set_security(bprm);
|
||||
+ /* already set based on script name */
|
||||
+ if (bprm->sh_bang)
|
||||
+ return 0;
|
||||
+ return aa_register(bprm);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_bprm_secureexec(struct linux_binprm *bprm)
|
||||
+{
|
||||
+ int ret = cap_bprm_secureexec(bprm);
|
||||
+
|
||||
+ if (!ret && (unsigned long)bprm->security & AA_SECURE_EXEC_NEEDED) {
|
||||
+ AA_DEBUG("%s: secureexec required for %s\n",
|
||||
+ __FUNCTION__, bprm->filename);
|
||||
+ ret = 1;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_sb_mount(char *dev_name, struct path *path, char *type,
|
||||
+ unsigned long flags, void *data)
|
||||
+{
|
||||
+ return aa_reject_syscall(current, GFP_KERNEL, "mount");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_umount(struct vfsmount *mnt, int flags)
|
||||
+{
|
||||
+ return aa_reject_syscall(current, GFP_KERNEL, "umount");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mask)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (!mnt || !mediated_filesystem(dir))
|
||||
+ goto out;
|
||||
+
|
||||
+ profile = aa_get_profile(current);
|
||||
+
|
||||
+ if (profile)
|
||||
+ error = aa_perm_dir(profile, "inode_mkdir", dentry, mnt,
|
||||
+ MAY_WRITE);
|
||||
+
|
||||
+ aa_put_profile(profile);
|
||||
+
|
||||
+out:
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_rmdir(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (!mnt || !mediated_filesystem(dir))
|
||||
+ goto out;
|
||||
+
|
||||
+ profile = aa_get_profile(current);
|
||||
+
|
||||
+ if (profile)
|
||||
+ error = aa_perm_dir(profile, "inode_rmdir", dentry, mnt,
|
||||
+ MAY_WRITE);
|
||||
+
|
||||
+ aa_put_profile(profile);
|
||||
+
|
||||
+out:
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int aa_permission(const char *operation, struct inode *inode,
|
||||
+ struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ int mask, int check)
|
||||
+{
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (mnt && mediated_filesystem(inode)) {
|
||||
+ struct aa_profile *profile;
|
||||
+
|
||||
+ profile = aa_get_profile(current);
|
||||
+ if (profile)
|
||||
+ error = aa_perm(profile, operation, dentry, mnt, mask,
|
||||
+ check);
|
||||
+ aa_put_profile(profile);
|
||||
+ }
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static inline int aa_mask_permissions(int mask)
|
||||
+{
|
||||
+ if (mask & MAY_APPEND)
|
||||
+ mask &= (MAY_READ | MAY_APPEND | MAY_EXEC);
|
||||
+ else
|
||||
+ mask &= (MAY_READ | MAY_WRITE | MAY_EXEC);
|
||||
+ return mask;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mask)
|
||||
+{
|
||||
+ return aa_permission("inode_create", dir, dentry, mnt, MAY_APPEND, 0);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_link(struct dentry *old_dentry,
|
||||
+ struct vfsmount *old_mnt, struct inode *dir,
|
||||
+ struct dentry *new_dentry,
|
||||
+ struct vfsmount *new_mnt)
|
||||
+{
|
||||
+ int error = 0;
|
||||
+ struct aa_profile *profile;
|
||||
+
|
||||
+ if (!old_mnt || !new_mnt || !mediated_filesystem(dir))
|
||||
+ goto out;
|
||||
+
|
||||
+ profile = aa_get_profile(current);
|
||||
+
|
||||
+ if (profile)
|
||||
+ error = aa_link(profile, new_dentry, new_mnt,
|
||||
+ old_dentry, old_mnt);
|
||||
+
|
||||
+ aa_put_profile(profile);
|
||||
+
|
||||
+out:
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_unlink(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
+{
|
||||
+ int check = 0;
|
||||
+
|
||||
+ if (S_ISDIR(dentry->d_inode->i_mode))
|
||||
+ check |= AA_CHECK_DIR;
|
||||
+ return aa_permission("inode_unlink", dir, dentry, mnt, MAY_WRITE,
|
||||
+ check);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_symlink(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, const char *old_name)
|
||||
+{
|
||||
+ return aa_permission("inode_symlink", dir, dentry, mnt, MAY_WRITE, 0);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mode, dev_t dev)
|
||||
+{
|
||||
+ return aa_permission("inode_mknod", dir, dentry, mnt, MAY_WRITE, 0);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_rename(struct inode *old_dir,
|
||||
+ struct dentry *old_dentry,
|
||||
+ struct vfsmount *old_mnt,
|
||||
+ struct inode *new_dir,
|
||||
+ struct dentry *new_dentry,
|
||||
+ struct vfsmount *new_mnt)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if ((!old_mnt && !new_mnt) || !mediated_filesystem(old_dir))
|
||||
+ goto out;
|
||||
+
|
||||
+ profile = aa_get_profile(current);
|
||||
+
|
||||
+ if (profile) {
|
||||
+ struct inode *inode = old_dentry->d_inode;
|
||||
+ int check = 0;
|
||||
+
|
||||
+ if (inode && S_ISDIR(inode->i_mode))
|
||||
+ check |= AA_CHECK_DIR;
|
||||
+ if (old_mnt)
|
||||
+ error = aa_perm(profile, "inode_rename", old_dentry,
|
||||
+ old_mnt, MAY_READ | MAY_WRITE, check);
|
||||
+
|
||||
+ if (!error && new_mnt) {
|
||||
+ error = aa_perm(profile, "inode_rename", new_dentry,
|
||||
+ new_mnt, MAY_WRITE, check);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ aa_put_profile(profile);
|
||||
+
|
||||
+out:
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_permission(struct inode *inode, int mask,
|
||||
+ struct nameidata *nd)
|
||||
+{
|
||||
+ int check = 0;
|
||||
+
|
||||
+ if (!nd || nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE))
|
||||
+ return 0;
|
||||
+ mask = aa_mask_permissions(mask);
|
||||
+ if (S_ISDIR(inode->i_mode)) {
|
||||
+ check |= AA_CHECK_DIR;
|
||||
+ /* allow traverse accesses to directories */
|
||||
+ mask &= ~MAY_EXEC;
|
||||
+ }
|
||||
+ return aa_permission("inode_permission", inode, nd->dentry, nd->mnt,
|
||||
+ mask, check);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct iattr *iattr)
|
||||
+{
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (!mnt)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (mediated_filesystem(dentry->d_inode)) {
|
||||
+ struct aa_profile *profile;
|
||||
+
|
||||
+ profile = aa_get_profile(current);
|
||||
+ /*
|
||||
+ * Mediate any attempt to change attributes of a file
|
||||
+ * (chmod, chown, chgrp, etc)
|
||||
+ */
|
||||
+ if (profile)
|
||||
+ error = aa_attr(profile, dentry, mnt, iattr);
|
||||
+
|
||||
+ aa_put_profile(profile);
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int aa_xattr_permission(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *operation, int mask,
|
||||
+ struct file *file)
|
||||
+{
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (mnt && mediated_filesystem(dentry->d_inode)) {
|
||||
+ struct aa_profile *profile = aa_get_profile(current);
|
||||
+ int check = file ? AA_CHECK_FD : 0;
|
||||
+
|
||||
+ if (profile)
|
||||
+ error = aa_perm_xattr(profile, operation, dentry, mnt,
|
||||
+ mask, check);
|
||||
+ aa_put_profile(profile);
|
||||
+ }
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags, struct file *file)
|
||||
+{
|
||||
+ int error = cap_inode_setxattr(dentry, mnt, name, value, size, flags,
|
||||
+ file);
|
||||
+
|
||||
+ if (!error)
|
||||
+ error = aa_xattr_permission(dentry, mnt, "xattr set",
|
||||
+ MAY_WRITE, file);
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, struct file *file)
|
||||
+{
|
||||
+ return aa_xattr_permission(dentry, mnt, "xattr get", MAY_READ, file);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct file *file)
|
||||
+{
|
||||
+ return aa_xattr_permission(dentry, mnt, "xattr list", MAY_READ, file);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_removexattr(struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, const char *name,
|
||||
+ struct file *file)
|
||||
+{
|
||||
+ return aa_xattr_permission(dentry, mnt, "xattr remove", MAY_WRITE,
|
||||
+ file);
|
||||
+}
|
||||
+
|
||||
+static int aa_file_permission(const char *op, struct file *file, int mask)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (!file_profile)
|
||||
+ goto out;
|
||||
+
|
||||
+ /*
|
||||
+ * If this file was opened under a different profile, we
|
||||
+ * revalidate the access against the current profile.
|
||||
+ */
|
||||
+ profile = aa_get_profile(current);
|
||||
+ if (profile && (file_profile != profile || mask & AA_MAY_LOCK)) {
|
||||
+ struct dentry *dentry = file->f_dentry;
|
||||
+ struct vfsmount *mnt = file->f_vfsmnt;
|
||||
+ struct inode *inode = dentry->d_inode;
|
||||
+ int check = AA_CHECK_FD;
|
||||
+
|
||||
+ /*
|
||||
+ * FIXME: We should remember which profiles we revalidated
|
||||
+ * against.
|
||||
+ */
|
||||
+ if (S_ISDIR(inode->i_mode))
|
||||
+ check |= AA_CHECK_DIR;
|
||||
+ error = aa_permission(op, inode, dentry, mnt, mask, check);
|
||||
+ }
|
||||
+ aa_put_profile(profile);
|
||||
+
|
||||
+out:
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_file_permission(struct file *file, int mask)
|
||||
+{
|
||||
+ return aa_file_permission("file_permission", file,
|
||||
+ aa_mask_permissions(mask));
|
||||
+}
|
||||
+
|
||||
+static inline int apparmor_file_lock (struct file *file, unsigned int cmd)
|
||||
+{
|
||||
+ int mask = AA_MAY_LOCK;
|
||||
+ if (cmd == F_WRLCK)
|
||||
+ mask |= MAY_WRITE;
|
||||
+ return aa_file_permission("file_lock", file, mask);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_file_alloc_security(struct file *file)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+
|
||||
+ profile = aa_get_profile(current);
|
||||
+ if (profile)
|
||||
+ file->f_security = profile;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void apparmor_file_free_security(struct file *file)
|
||||
+{
|
||||
+ struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
|
||||
+
|
||||
+ aa_put_profile(file_profile);
|
||||
+}
|
||||
+
|
||||
+static inline int aa_mmap(struct file *file, const char *operation,
|
||||
+ unsigned long prot, unsigned long flags)
|
||||
+{
|
||||
+ struct dentry *dentry;
|
||||
+ int mask = 0;
|
||||
+
|
||||
+ if (!file || !file->f_security)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (prot & PROT_READ)
|
||||
+ mask |= MAY_READ;
|
||||
+ /* Private mappings don't require write perms since they don't
|
||||
+ * write back to the files */
|
||||
+ if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
|
||||
+ mask |= MAY_WRITE;
|
||||
+ if (prot & PROT_EXEC)
|
||||
+ mask |= AA_EXEC_MMAP;
|
||||
+
|
||||
+ dentry = file->f_dentry;
|
||||
+ return aa_permission(operation, dentry->d_inode, dentry,
|
||||
+ file->f_vfsmnt, mask, AA_CHECK_FD);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
|
||||
+ unsigned long prot, unsigned long flags,
|
||||
+ unsigned long addr, unsigned long addr_only)
|
||||
+{
|
||||
+ if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO)) {
|
||||
+ struct aa_profile *profile = aa_get_profile(current);
|
||||
+ if (profile)
|
||||
+ /* future control check here */
|
||||
+ return -EACCES;
|
||||
+ else
|
||||
+ return -EACCES;
|
||||
+ aa_put_profile(profile);
|
||||
+ }
|
||||
+
|
||||
+ return aa_mmap(file, "file_mmap", prot, flags);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_file_mprotect(struct vm_area_struct *vma,
|
||||
+ unsigned long reqprot, unsigned long prot)
|
||||
+{
|
||||
+ return aa_mmap(vma->vm_file, "file_mprotect", prot,
|
||||
+ !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_task_alloc_security(struct task_struct *task)
|
||||
+{
|
||||
+ return aa_clone(task);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Called from IRQ context from RCU callback.
|
||||
+ */
|
||||
+static void apparmor_task_free_security(struct task_struct *task)
|
||||
+{
|
||||
+ aa_release(task);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_getprocattr(struct task_struct *task, char *name,
|
||||
+ char **value)
|
||||
+{
|
||||
+ unsigned len;
|
||||
+ int error;
|
||||
+ struct aa_profile *profile;
|
||||
+
|
||||
+ /* AppArmor only supports the "current" process attribute */
|
||||
+ if (strcmp(name, "current") != 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* must be task querying itself or admin */
|
||||
+ if (current != task && !capable(CAP_SYS_ADMIN))
|
||||
+ return -EPERM;
|
||||
+
|
||||
+ profile = aa_get_profile(task);
|
||||
+ error = aa_getprocattr(profile, value, &len);
|
||||
+ aa_put_profile(profile);
|
||||
+ if (!error)
|
||||
+ error = len;
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_setprocattr(struct task_struct *task, char *name,
|
||||
+ void *value, size_t size)
|
||||
+{
|
||||
+ char *command, *args;
|
||||
+ int error;
|
||||
+
|
||||
+ if (strcmp(name, "current") != 0 || size == 0 || size >= PAGE_SIZE)
|
||||
+ return -EINVAL;
|
||||
+ args = value;
|
||||
+ args[size] = '\0';
|
||||
+ args = strstrip(args);
|
||||
+ command = strsep(&args, " ");
|
||||
+ if (!args)
|
||||
+ return -EINVAL;
|
||||
+ while (isspace(*args))
|
||||
+ args++;
|
||||
+ if (!*args)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (strcmp(command, "changehat") == 0) {
|
||||
+ if (current != task)
|
||||
+ return -EACCES;
|
||||
+ error = aa_setprocattr_changehat(args);
|
||||
+ } else if (strcmp(command, "changeprofile") == 0) {
|
||||
+ if (current != task)
|
||||
+ return -EACCES;
|
||||
+ error = aa_setprocattr_changeprofile(args);
|
||||
+ } else if (strcmp(command, "setprofile") == 0) {
|
||||
+ struct aa_profile *profile;
|
||||
+
|
||||
+ /* Only an unconfined process with admin capabilities
|
||||
+ * may change the profile of another task.
|
||||
+ */
|
||||
+
|
||||
+ if (!capable(CAP_SYS_ADMIN))
|
||||
+ return -EACCES;
|
||||
+
|
||||
+ profile = aa_get_profile(current);
|
||||
+ if (profile) {
|
||||
+ struct aa_audit sa;
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = "profile_set";
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+ sa.task = task->pid;
|
||||
+ sa.info = "from confined process";
|
||||
+ aa_audit_reject(profile, &sa);
|
||||
+ aa_put_profile(profile);
|
||||
+ return -EACCES;
|
||||
+ }
|
||||
+ error = aa_setprocattr_setprofile(task, args);
|
||||
+ } else {
|
||||
+ struct aa_audit sa;
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = "setprocattr";
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+ sa.info = "invalid command";
|
||||
+ sa.name = command;
|
||||
+ sa.task = task->pid;
|
||||
+ aa_audit_reject(NULL, &sa);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if (!error)
|
||||
+ error = size;
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+struct security_operations apparmor_ops = {
|
||||
+ .ptrace = apparmor_ptrace,
|
||||
+ .capget = cap_capget,
|
||||
+ .capset_check = cap_capset_check,
|
||||
+ .capset_set = cap_capset_set,
|
||||
+ .sysctl = apparmor_sysctl,
|
||||
+ .capable = apparmor_capable,
|
||||
+ .syslog = cap_syslog,
|
||||
+
|
||||
+ .netlink_send = cap_netlink_send,
|
||||
+ .netlink_recv = cap_netlink_recv,
|
||||
+
|
||||
+ .bprm_apply_creds = cap_bprm_apply_creds,
|
||||
+ .bprm_set_security = apparmor_bprm_set_security,
|
||||
+ .bprm_secureexec = apparmor_bprm_secureexec,
|
||||
+
|
||||
+ .sb_mount = apparmor_sb_mount,
|
||||
+ .sb_umount = apparmor_umount,
|
||||
+
|
||||
+ .inode_mkdir = apparmor_inode_mkdir,
|
||||
+ .inode_rmdir = apparmor_inode_rmdir,
|
||||
+ .inode_create = apparmor_inode_create,
|
||||
+ .inode_link = apparmor_inode_link,
|
||||
+ .inode_unlink = apparmor_inode_unlink,
|
||||
+ .inode_symlink = apparmor_inode_symlink,
|
||||
+ .inode_mknod = apparmor_inode_mknod,
|
||||
+ .inode_rename = apparmor_inode_rename,
|
||||
+ .inode_permission = apparmor_inode_permission,
|
||||
+ .inode_setattr = apparmor_inode_setattr,
|
||||
+ .inode_setxattr = apparmor_inode_setxattr,
|
||||
+ .inode_getxattr = apparmor_inode_getxattr,
|
||||
+ .inode_listxattr = apparmor_inode_listxattr,
|
||||
+ .inode_removexattr = apparmor_inode_removexattr,
|
||||
+ .file_permission = apparmor_file_permission,
|
||||
+ .file_alloc_security = apparmor_file_alloc_security,
|
||||
+ .file_free_security = apparmor_file_free_security,
|
||||
+ .file_mmap = apparmor_file_mmap,
|
||||
+ .file_mprotect = apparmor_file_mprotect,
|
||||
+ .file_lock = apparmor_file_lock,
|
||||
+
|
||||
+ .task_alloc_security = apparmor_task_alloc_security,
|
||||
+ .task_free_security = apparmor_task_free_security,
|
||||
+ .task_post_setuid = cap_task_post_setuid,
|
||||
+ .task_reparent_to_init = cap_task_reparent_to_init,
|
||||
+
|
||||
+ .getprocattr = apparmor_getprocattr,
|
||||
+ .setprocattr = apparmor_setprocattr,
|
||||
+};
|
||||
+
|
||||
+void info_message(const char *str)
|
||||
+{
|
||||
+ struct aa_audit sa;
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+ sa.info = str;
|
||||
+ printk(KERN_INFO "AppArmor: %s\n", str);
|
||||
+ if (audit_enabled)
|
||||
+ aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS);
|
||||
+}
|
||||
+
|
||||
+static int __init apparmor_init(void)
|
||||
+{
|
||||
+ int error;
|
||||
+
|
||||
+ if (!apparmor_enabled) {
|
||||
+ info_message("AppArmor disabled by boottime parameter\n");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if ((error = create_apparmorfs())) {
|
||||
+ AA_ERROR("Unable to activate AppArmor filesystem\n");
|
||||
+ goto createfs_out;
|
||||
+ }
|
||||
+
|
||||
+ if ((error = alloc_default_namespace())){
|
||||
+ AA_ERROR("Unable to allocate default profile namespace\n");
|
||||
+ goto alloc_out;
|
||||
+ }
|
||||
+
|
||||
+ if ((error = register_security(&apparmor_ops))) {
|
||||
+ AA_ERROR("Unable to register AppArmor\n");
|
||||
+ goto register_security_out;
|
||||
+ }
|
||||
+
|
||||
+ /* Report that AppArmor successfully initialized */
|
||||
+ apparmor_initialized = 1;
|
||||
+ if (apparmor_complain)
|
||||
+ info_message("AppArmor initialized: complainmode enabled");
|
||||
+ else
|
||||
+ info_message("AppArmor initialized");
|
||||
+
|
||||
+ return error;
|
||||
+
|
||||
+register_security_out:
|
||||
+ free_default_namespace();
|
||||
+
|
||||
+alloc_out:
|
||||
+ destroy_apparmorfs();
|
||||
+
|
||||
+createfs_out:
|
||||
+ return error;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+security_initcall(apparmor_init);
|
||||
+
|
||||
+void apparmor_disable(void)
|
||||
+{
|
||||
+ /* Remove and release all the profiles on the profile list. */
|
||||
+ mutex_lock(&aa_interface_lock);
|
||||
+ aa_profile_ns_list_release();
|
||||
+
|
||||
+ /* FIXME: cleanup profiles references on files */
|
||||
+ free_default_namespace();
|
||||
+
|
||||
+ /*
|
||||
+ * Delay for an rcu cycle to make sure that all active task
|
||||
+ * context readers have finished, and all profiles have been
|
||||
+ * freed by their rcu callbacks.
|
||||
+ */
|
||||
+ synchronize_rcu();
|
||||
+
|
||||
+ destroy_apparmorfs();
|
||||
+ mutex_unlock(&aa_interface_lock);
|
||||
+
|
||||
+ apparmor_initialized = 0;
|
||||
+
|
||||
+ info_message("AppArmor protection removed");
|
||||
+}
|
||||
+
|
||||
+MODULE_DESCRIPTION("AppArmor process confinement");
|
||||
+MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");
|
||||
+MODULE_LICENSE("GPL");
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,408 +0,0 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: AppArmor: Simplified network controls for AppArmor
|
||||
|
||||
Simple network control determining which network families a confined
|
||||
application has access to.
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/Makefile | 7 +
|
||||
security/apparmor/apparmor.h | 9 ++
|
||||
security/apparmor/lsm.c | 129 ++++++++++++++++++++++++++++++++++-
|
||||
security/apparmor/main.c | 107 ++++++++++++++++++++++++++++-
|
||||
security/apparmor/module_interface.c | 26 ++++++-
|
||||
5 files changed, 271 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/security/apparmor/Makefile
|
||||
+++ b/security/apparmor/Makefile
|
||||
@@ -8,6 +8,11 @@ apparmor-y := main.o list.o procattr.o l
|
||||
quiet_cmd_make-caps = GEN $@
|
||||
cmd_make-caps = sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z > $@
|
||||
|
||||
-$(obj)/main.o : $(obj)/capability_names.h
|
||||
+quiet_cmd_make-af = GEN $@
|
||||
+cmd_make-af = sed -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "s/^\#define[ \\t]\\+AF_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z > $@
|
||||
+
|
||||
+$(obj)/main.o : $(obj)/capability_names.h $(obj)/af_names.h
|
||||
$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
|
||||
$(call cmd,make-caps)
|
||||
+$(obj)/af_names.h : $(srctree)/include/linux/socket.h
|
||||
+ $(call cmd,make-af)
|
||||
--- a/security/apparmor/apparmor.h
|
||||
+++ b/security/apparmor/apparmor.h
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/rcupdate.h>
|
||||
+#include <linux/socket.h>
|
||||
+#include <net/sock.h>
|
||||
|
||||
/*
|
||||
* We use MAY_READ, MAY_WRITE, MAY_EXEC, MAY_APPEND and the following flags
|
||||
@@ -212,6 +214,9 @@ struct aa_profile {
|
||||
struct list_head task_contexts;
|
||||
spinlock_t lock;
|
||||
unsigned long int_flags;
|
||||
+ u16 network_families[AF_MAX];
|
||||
+ u16 audit_network[AF_MAX];
|
||||
+ u16 quiet_network[AF_MAX];
|
||||
};
|
||||
|
||||
extern struct list_head profile_ns_list;
|
||||
@@ -258,6 +263,7 @@ struct aa_audit {
|
||||
int request_mask, denied_mask, audit_mask;
|
||||
struct iattr *iattr;
|
||||
pid_t task, parent;
|
||||
+ int family, type, protocol;
|
||||
int error_code;
|
||||
};
|
||||
|
||||
@@ -319,6 +325,9 @@ extern void aa_change_task_context(struc
|
||||
struct aa_profile *previous_profile);
|
||||
extern int aa_may_ptrace(struct aa_task_context *cxt,
|
||||
struct aa_profile *tracee);
|
||||
+extern int aa_net_perm(struct aa_profile *profile, char *operation,
|
||||
+ int family, int type, int protocol);
|
||||
+extern int aa_revalidate_sk(struct sock *sk, char *operation);
|
||||
|
||||
/* lsm.c */
|
||||
extern int apparmor_initialized;
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/audit.h>
|
||||
+#include <net/sock.h>
|
||||
|
||||
#include "apparmor.h"
|
||||
#include "inline.h"
|
||||
@@ -680,6 +681,117 @@ static void apparmor_task_free_security(
|
||||
aa_release(task);
|
||||
}
|
||||
|
||||
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (kern)
|
||||
+ return 0;
|
||||
+
|
||||
+ profile = aa_get_profile(current);
|
||||
+ if (profile)
|
||||
+ error = aa_net_perm(profile, "socket_create", family,
|
||||
+ type, protocol);
|
||||
+ aa_put_profile(profile);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_post_create(struct socket *sock, int family,
|
||||
+ int type, int protocol, int kern)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ if (kern)
|
||||
+ return 0;
|
||||
+
|
||||
+ return aa_revalidate_sk(sk, "socket_post_create");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_bind(struct socket *sock,
|
||||
+ struct sockaddr *address, int addrlen)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(sk, "socket_bind");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_connect(struct socket *sock,
|
||||
+ struct sockaddr *address, int addrlen)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(sk, "socket_connect");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_listen(struct socket *sock, int backlog)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(sk, "socket_listen");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(sk, "socket_accept");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_sendmsg(struct socket *sock,
|
||||
+ struct msghdr *msg, int size)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(sk, "socket_sendmsg");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_recvmsg(struct socket *sock,
|
||||
+ struct msghdr *msg, int size, int flags)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(sk, "socket_recvmsg");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getsockname(struct socket *sock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(sk, "socket_getsockname");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getpeername(struct socket *sock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(sk, "socket_getpeername");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
|
||||
+ int optname)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(sk, "socket_getsockopt");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
|
||||
+ int optname)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(sk, "socket_setsockopt");
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_shutdown(struct socket *sock, int how)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(sk, "socket_shutdown");
|
||||
+}
|
||||
+
|
||||
static int apparmor_getprocattr(struct task_struct *task, char *name,
|
||||
char **value)
|
||||
{
|
||||
@@ -780,9 +892,6 @@ struct security_operations apparmor_ops
|
||||
.capable = apparmor_capable,
|
||||
.syslog = cap_syslog,
|
||||
|
||||
- .netlink_send = cap_netlink_send,
|
||||
- .netlink_recv = cap_netlink_recv,
|
||||
-
|
||||
.bprm_apply_creds = cap_bprm_apply_creds,
|
||||
.bprm_set_security = apparmor_bprm_set_security,
|
||||
.bprm_secureexec = apparmor_bprm_secureexec,
|
||||
@@ -820,6 +929,20 @@ struct security_operations apparmor_ops
|
||||
|
||||
.getprocattr = apparmor_getprocattr,
|
||||
.setprocattr = apparmor_setprocattr,
|
||||
+
|
||||
+ .socket_create = apparmor_socket_create,
|
||||
+ .socket_post_create = apparmor_socket_post_create,
|
||||
+ .socket_bind = apparmor_socket_bind,
|
||||
+ .socket_connect = apparmor_socket_connect,
|
||||
+ .socket_listen = apparmor_socket_listen,
|
||||
+ .socket_accept = apparmor_socket_accept,
|
||||
+ .socket_sendmsg = apparmor_socket_sendmsg,
|
||||
+ .socket_recvmsg = apparmor_socket_recvmsg,
|
||||
+ .socket_getsockname = apparmor_socket_getsockname,
|
||||
+ .socket_getpeername = apparmor_socket_getpeername,
|
||||
+ .socket_getsockopt = apparmor_socket_getsockopt,
|
||||
+ .socket_setsockopt = apparmor_socket_setsockopt,
|
||||
+ .socket_shutdown = apparmor_socket_shutdown,
|
||||
};
|
||||
|
||||
void info_message(const char *str)
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -14,6 +14,9 @@
|
||||
#include <linux/audit.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/ptrace.h>
|
||||
+#include <linux/socket.h>
|
||||
+#include <linux/net.h>
|
||||
+#include <net/sock.h>
|
||||
|
||||
#include "apparmor.h"
|
||||
|
||||
@@ -116,6 +119,24 @@ static void aa_audit_file_mask(struct au
|
||||
audit_log_format(ab, " %s=\"%s::%s\"", name, user, other);
|
||||
}
|
||||
|
||||
+static const char *address_families[] = {
|
||||
+#include "af_names.h"
|
||||
+};
|
||||
+
|
||||
+static const char *sock_types[] = {
|
||||
+ "unknown(0)",
|
||||
+ "stream",
|
||||
+ "dgram",
|
||||
+ "raw",
|
||||
+ "rdm",
|
||||
+ "seqpacket",
|
||||
+ "dccp",
|
||||
+ "unknown(7)",
|
||||
+ "unknown(8)",
|
||||
+ "unknown(9)",
|
||||
+ "packet",
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* aa_audit - Log an audit event to the audit subsystem
|
||||
* @profile: profile to check against
|
||||
@@ -187,7 +208,25 @@ static int aa_audit_base(struct aa_profi
|
||||
audit_log_untrustedstring(ab, sa->name2);
|
||||
}
|
||||
|
||||
- audit_log_format(ab, " pid=%d", current->pid);
|
||||
+ if (sa->family || sa->type) {
|
||||
+ if (address_families[sa->family])
|
||||
+ audit_log_format(ab, " family=\"%s\"",
|
||||
+ address_families[sa->family]);
|
||||
+ else
|
||||
+ audit_log_format(ab, " family=\"unknown(%d)\"",
|
||||
+ sa->family);
|
||||
+
|
||||
+ if (sock_types[sa->type])
|
||||
+ audit_log_format(ab, " sock_type=\"%s\"",
|
||||
+ sock_types[sa->type]);
|
||||
+ else
|
||||
+ audit_log_format(ab, " sock_type=\"unknown(%d)\"",
|
||||
+ sa->type);
|
||||
+
|
||||
+ audit_log_format(ab, " protocol=%d", sa->protocol);
|
||||
+ }
|
||||
+
|
||||
+ audit_log_format(ab, " pid=%d", current->pid);
|
||||
|
||||
if (profile) {
|
||||
audit_log_format(ab, " profile=");
|
||||
@@ -767,6 +806,72 @@ int aa_link(struct aa_profile *profile,
|
||||
|
||||
return error;
|
||||
}
|
||||
+
|
||||
+int aa_net_perm(struct aa_profile *profile, char *operation,
|
||||
+ int family, int type, int protocol)
|
||||
+{
|
||||
+ struct aa_audit sa;
|
||||
+ int error = 0;
|
||||
+ u16 family_mask, audit_mask, quiet_mask;
|
||||
+
|
||||
+ if ((family < 0) || (family >= AF_MAX))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if ((type < 0) || (type >= SOCK_MAX))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* unix domain and netlink sockets are handled by ipc */
|
||||
+ if (family == AF_UNIX || family == AF_NETLINK)
|
||||
+ return 0;
|
||||
+
|
||||
+ family_mask = profile->network_families[family];
|
||||
+ audit_mask = profile->audit_network[family];
|
||||
+ quiet_mask = profile->quiet_network[family];
|
||||
+
|
||||
+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
|
||||
+
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = operation;
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+ sa.family = family;
|
||||
+ sa.type = type;
|
||||
+ sa.protocol = protocol;
|
||||
+ sa.error_code = error;
|
||||
+
|
||||
+ if (likely(!error)) {
|
||||
+ if (!PROFILE_AUDIT(profile) && !(family_mask & audit_mask))
|
||||
+ return 0;
|
||||
+ } else if (!((1 << type) & ~quiet_mask)) {
|
||||
+ return error;
|
||||
+ }
|
||||
+
|
||||
+ error = aa_audit(profile, &sa);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_revalidate_sk(struct sock *sk, char *operation)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ /* this is some debugging code to flush out the network hooks that
|
||||
+ that are called in interrupt context */
|
||||
+ if (in_interrupt()) {
|
||||
+ printk("AppArmor Debug: Hook being called from interrupt context\n");
|
||||
+ dump_stack();
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ profile = aa_get_profile(current);
|
||||
+ if (profile)
|
||||
+ error = aa_net_perm(profile, operation,
|
||||
+ sk->sk_family, sk->sk_type,
|
||||
+ sk->sk_protocol);
|
||||
+ aa_put_profile(profile);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
|
||||
/*******************************
|
||||
* Global task related functions
|
||||
--- a/security/apparmor/module_interface.c
|
||||
+++ b/security/apparmor/module_interface.c
|
||||
@@ -321,8 +321,8 @@ static struct aa_profile *aa_unpack_prof
|
||||
struct aa_audit *sa)
|
||||
{
|
||||
struct aa_profile *profile = NULL;
|
||||
-
|
||||
- int error = -EPROTO;
|
||||
+ size_t size = 0;
|
||||
+ int i, error = -EPROTO;
|
||||
|
||||
profile = alloc_aa_profile();
|
||||
if (!profile)
|
||||
@@ -355,6 +355,28 @@ static struct aa_profile *aa_unpack_prof
|
||||
if (!aa_is_u32(e, &(profile->set_caps), NULL))
|
||||
goto fail;
|
||||
|
||||
+ size = aa_is_array(e, "net_allowed_af");
|
||||
+ if (size) {
|
||||
+ if (size > AF_MAX)
|
||||
+ goto fail;
|
||||
+
|
||||
+ for (i = 0; i < size; i++) {
|
||||
+ if (!aa_is_u16(e, &profile->network_families[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_u16(e, &profile->audit_network[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_u16(e, &profile->quiet_network[i], NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ if (!aa_is_nameX(e, AA_ARRAYEND, NULL))
|
||||
+ goto fail;
|
||||
+ /* allow unix domain and netlink sockets they are handled
|
||||
+ * by IPC
|
||||
+ */
|
||||
+ }
|
||||
+ profile->network_families[AF_UNIX] = 0xffff;
|
||||
+ profile->network_families[AF_NETLINK] = 0xffff;
|
||||
+
|
||||
/* get file rules */
|
||||
profile->file_rules = aa_unpack_dfa(e);
|
||||
if (IS_ERR(profile->file_rules)) {
|
||||
@@ -1,78 +0,0 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: [PATCH] apparmor: convert apparmor_inode_permission to path
|
||||
|
||||
patches.apparmor/add-security_path_permission added the ->path_permission
|
||||
call. This patch converts apparmor_inode_permission to
|
||||
apparmor_path_permission. The former is now a pass-all, which is how
|
||||
it behaved in 2.6.26 if a NULL nameidata was passed.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
security/apparmor/lsm.c | 41 +++++++++++++++++++++++++++--------------
|
||||
1 file changed, 27 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -448,21 +448,9 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
-static int apparmor_inode_permission(struct inode *inode, int mask,
|
||||
- struct nameidata *nd)
|
||||
+static int apparmor_inode_permission(struct inode *inode, int mask)
|
||||
{
|
||||
- int check = 0;
|
||||
-
|
||||
- if (!nd || nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE))
|
||||
- return 0;
|
||||
- mask = aa_mask_permissions(mask);
|
||||
- if (S_ISDIR(inode->i_mode)) {
|
||||
- check |= AA_CHECK_DIR;
|
||||
- /* allow traverse accesses to directories */
|
||||
- mask &= ~MAY_EXEC;
|
||||
- }
|
||||
- return aa_permission("inode_permission", inode, nd->dentry, nd->mnt,
|
||||
- mask, check);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
@@ -656,6 +644,29 @@ static int apparmor_file_mprotect(struct
|
||||
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
|
||||
}
|
||||
|
||||
+static int apparmor_path_permission(struct path *path, int mask)
|
||||
+{
|
||||
+ struct inode *inode;
|
||||
+ int check = 0;
|
||||
+
|
||||
+ if (!path)
|
||||
+ return 0;
|
||||
+
|
||||
+ inode = path->dentry->d_inode;
|
||||
+
|
||||
+ mask = aa_mask_permissions(mask);
|
||||
+ if (S_ISDIR(inode->i_mode)) {
|
||||
+ check |= AA_CHECK_DIR;
|
||||
+ /* allow traverse accesses to directories */
|
||||
+ mask &= ~MAY_EXEC;
|
||||
+ if (!mask)
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return aa_permission("inode_permission", inode, path->dentry,
|
||||
+ path->mnt, mask, check);
|
||||
+}
|
||||
+
|
||||
static int apparmor_task_alloc_security(struct task_struct *task)
|
||||
{
|
||||
return aa_clone(task);
|
||||
@@ -800,6 +811,8 @@ struct security_operations apparmor_ops
|
||||
.file_mprotect = apparmor_file_mprotect,
|
||||
.file_lock = apparmor_file_lock,
|
||||
|
||||
+ .path_permission = apparmor_path_permission,
|
||||
+
|
||||
.task_alloc_security = apparmor_task_alloc_security,
|
||||
.task_free_security = apparmor_task_free_security,
|
||||
.task_post_setuid = cap_task_post_setuid,
|
||||
@@ -1,55 +0,0 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: apparmor: use new ptrace security_operations
|
||||
|
||||
This patch implements the new ptrace security_operations members.
|
||||
|
||||
->ptrace was changed to ->ptrace_may_access and ->ptrace_traceme.
|
||||
|
||||
The apparmor versions are really just wrappers for the old function.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
|
||||
---
|
||||
security/apparmor/lsm.c | 17 +++++++++++++++--
|
||||
1 file changed, 15 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -158,7 +158,7 @@ static int aa_reject_syscall(struct task
|
||||
}
|
||||
|
||||
static int apparmor_ptrace(struct task_struct *parent,
|
||||
- struct task_struct *child, unsigned int mode)
|
||||
+ struct task_struct *child)
|
||||
{
|
||||
struct aa_task_context *cxt;
|
||||
int error = 0;
|
||||
@@ -207,6 +207,18 @@ static int apparmor_ptrace(struct task_s
|
||||
return error;
|
||||
}
|
||||
|
||||
+static int apparmor_ptrace_may_access(struct task_struct *child,
|
||||
+ unsigned int mode)
|
||||
+{
|
||||
+ return apparmor_ptrace(child->parent, child);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int apparmor_ptrace_traceme(struct task_struct *parent)
|
||||
+{
|
||||
+ return apparmor_ptrace(parent, current);
|
||||
+}
|
||||
+
|
||||
static int apparmor_capable(struct task_struct *task, int cap)
|
||||
{
|
||||
int error;
|
||||
@@ -899,7 +911,8 @@ static int apparmor_task_setrlimit(unsig
|
||||
}
|
||||
|
||||
struct security_operations apparmor_ops = {
|
||||
- .ptrace = apparmor_ptrace,
|
||||
+ .ptrace_may_access = apparmor_ptrace_may_access,
|
||||
+ .ptrace_traceme = apparmor_ptrace_traceme,
|
||||
.capget = cap_capget,
|
||||
.capset_check = cap_capset_check,
|
||||
.capset_set = cap_capset_set,
|
||||
@@ -1,461 +0,0 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: AppArmor: per profile controls for system rlimits
|
||||
|
||||
Provide contol of rlimits on a per profile basis. Each profile provides
|
||||
a per limit contol and corresponding hard limit value, such that when a
|
||||
profile becomes attached to a task it sets the tasks limits to be <= to
|
||||
the profiles specified limits. Note: the profile limit value will not
|
||||
raise a tasks limit if it is already less than the profile mandates.
|
||||
|
||||
In addition to setting a tasks limits, the ability to set limits on
|
||||
a confined task are controlled. AppArmor only controls the raising
|
||||
of a tasks limits Tasks with CAP_SYS_RESOURCE can have their hard limits
|
||||
raised up to the value specified by the profile. AppArmor does not
|
||||
prevent a task for lowering its hard limits, nor does it provide
|
||||
additional control on soft limits.
|
||||
|
||||
AppArmor only controls the limits specified in a profile so that
|
||||
any limit not specified is free to be modified subject to standard
|
||||
linux limitations.
|
||||
|
||||
---
|
||||
security/apparmor/apparmor.h | 23 ++++++
|
||||
security/apparmor/apparmorfs.c | 2
|
||||
security/apparmor/lsm.c | 16 ++++
|
||||
security/apparmor/main.c | 132 +++++++++++++++++++++++++++++++----
|
||||
security/apparmor/module_interface.c | 56 ++++++++++++++
|
||||
5 files changed, 215 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/security/apparmor/apparmor.h
|
||||
+++ b/security/apparmor/apparmor.h
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/rcupdate.h>
|
||||
+#include <linux/resource.h>
|
||||
#include <linux/socket.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
@@ -139,6 +140,18 @@ extern unsigned int apparmor_path_max;
|
||||
|
||||
#define AA_ERROR(fmt, args...) printk(KERN_ERR "AppArmor: " fmt, ##args)
|
||||
|
||||
+/* struct aa_rlimit - rlimits settings for the profile
|
||||
+ * @mask: which hard limits to set
|
||||
+ * @limits: rlimit values that override task limits
|
||||
+ *
|
||||
+ * AppArmor rlimits are used to set confined task rlimits. Only the
|
||||
+ * limits specified in @mask will be controlled by apparmor.
|
||||
+ */
|
||||
+struct aa_rlimit {
|
||||
+ unsigned int mask;
|
||||
+ struct rlimit limits[RLIM_NLIMITS];
|
||||
+};
|
||||
+
|
||||
struct aa_profile;
|
||||
|
||||
/* struct aa_namespace - namespace for a set of profiles
|
||||
@@ -173,6 +186,8 @@ struct aa_namespace {
|
||||
* @audit_caps: caps that are to be audited
|
||||
* @quiet_caps: caps that should not be audited
|
||||
* @capabilities: capabilities granted by the process
|
||||
+ * @rlimits: rlimits for the profile
|
||||
+ * @task_count: how many tasks the profile is attached to
|
||||
* @count: reference count of the profile
|
||||
* @task_contexts: list of tasks confined by profile
|
||||
* @lock: lock for the task_contexts list
|
||||
@@ -210,6 +225,9 @@ struct aa_profile {
|
||||
kernel_cap_t audit_caps;
|
||||
kernel_cap_t quiet_caps;
|
||||
|
||||
+ struct aa_rlimit rlimits;
|
||||
+ unsigned int task_count;
|
||||
+
|
||||
struct kref count;
|
||||
struct list_head task_contexts;
|
||||
spinlock_t lock;
|
||||
@@ -261,6 +279,7 @@ struct aa_audit {
|
||||
const char *name2;
|
||||
const char *name3;
|
||||
int request_mask, denied_mask, audit_mask;
|
||||
+ int rlimit;
|
||||
struct iattr *iattr;
|
||||
pid_t task, parent;
|
||||
int family, type, protocol;
|
||||
@@ -328,6 +347,10 @@ extern int aa_may_ptrace(struct aa_task_
|
||||
extern int aa_net_perm(struct aa_profile *profile, char *operation,
|
||||
int family, int type, int protocol);
|
||||
extern int aa_revalidate_sk(struct sock *sk, char *operation);
|
||||
+extern int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
|
||||
+ struct rlimit *new_rlim);
|
||||
+extern void aa_set_rlimits(struct task_struct *task, struct aa_profile *profile);
|
||||
+
|
||||
|
||||
/* lsm.c */
|
||||
extern int apparmor_initialized;
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -106,7 +106,7 @@ static ssize_t aa_features_read(struct f
|
||||
{
|
||||
const char *features = "file=3.0 capability=2.0 network=1.0 "
|
||||
"change_hat=1.5 change_profile=1.0 "
|
||||
- "aanamespaces=1.0";
|
||||
+ "aanamespaces=1.0 rlimit=1.0";
|
||||
|
||||
return simple_read_from_buffer(buf, size, ppos, features,
|
||||
strlen(features));
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -883,6 +883,21 @@ static int apparmor_setprocattr(struct t
|
||||
return error;
|
||||
}
|
||||
|
||||
+static int apparmor_task_setrlimit(unsigned int resource,
|
||||
+ struct rlimit *new_rlim)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ profile = aa_get_profile(current);
|
||||
+ if (profile) {
|
||||
+ error = aa_task_setrlimit(profile, resource, new_rlim);
|
||||
+ }
|
||||
+ aa_put_profile(profile);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
struct security_operations apparmor_ops = {
|
||||
.ptrace = apparmor_ptrace,
|
||||
.capget = cap_capget,
|
||||
@@ -926,6 +941,7 @@ struct security_operations apparmor_ops
|
||||
.task_free_security = apparmor_task_free_security,
|
||||
.task_post_setuid = cap_task_post_setuid,
|
||||
.task_reparent_to_init = cap_task_reparent_to_init,
|
||||
+ .task_setrlimit = apparmor_task_setrlimit,
|
||||
|
||||
.getprocattr = apparmor_getprocattr,
|
||||
.setprocattr = apparmor_setprocattr,
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -177,6 +177,9 @@ static int aa_audit_base(struct aa_profi
|
||||
if (sa->request_mask)
|
||||
audit_log_format(ab, " fsuid=%d", current->fsuid);
|
||||
|
||||
+ if (sa->rlimit)
|
||||
+ audit_log_format(ab, " rlimit=%d", sa->rlimit - 1);
|
||||
+
|
||||
if (sa->iattr) {
|
||||
struct iattr *iattr = sa->iattr;
|
||||
|
||||
@@ -872,6 +875,79 @@ int aa_revalidate_sk(struct sock *sk, ch
|
||||
|
||||
return error;
|
||||
}
|
||||
+/**
|
||||
+ * aa_task_setrlimit - test permission to set an rlimit
|
||||
+ * @profile - profile confining the task
|
||||
+ * @resource - the resource being set
|
||||
+ * @new_rlim - the new resource limit
|
||||
+ *
|
||||
+ * Control raising the processes hard limit.
|
||||
+ */
|
||||
+int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
|
||||
+ struct rlimit *new_rlim)
|
||||
+{
|
||||
+ struct aa_audit sa;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = "setrlimit";
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+ sa.rlimit = resource + 1;
|
||||
+
|
||||
+ if (profile->rlimits.mask & (1 << resource) &&
|
||||
+ new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max) {
|
||||
+ sa.error_code = -EACCES;
|
||||
+
|
||||
+ error = aa_audit(profile, &sa);
|
||||
+ }
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int aa_rlimit_nproc(struct aa_profile *profile) {
|
||||
+ if (profile && (profile->rlimits.mask & (1 << RLIMIT_NPROC)) &&
|
||||
+ profile->task_count >= profile->rlimits.limits[RLIMIT_NPROC].rlim_max)
|
||||
+ return -EAGAIN;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void aa_set_rlimits(struct task_struct *task, struct aa_profile *profile)
|
||||
+{
|
||||
+ int i, mask;
|
||||
+
|
||||
+ if (!profile)
|
||||
+ return;
|
||||
+
|
||||
+ if (!profile->rlimits.mask)
|
||||
+ return;
|
||||
+
|
||||
+ task_lock(task->group_leader);
|
||||
+ mask = 1;
|
||||
+ for (i = 0; i < RLIM_NLIMITS; i++, mask <<= 1) {
|
||||
+ struct rlimit new_rlim, *old_rlim;
|
||||
+
|
||||
+ /* check to see if NPROC which is per profile and handled
|
||||
+ * in clone/exec or whether this is a limit to be set
|
||||
+ * can't set cpu limit either right now
|
||||
+ */
|
||||
+ if (i == RLIMIT_NPROC || i == RLIMIT_CPU)
|
||||
+ continue;
|
||||
+
|
||||
+ old_rlim = task->signal->rlim + i;
|
||||
+ new_rlim = *old_rlim;
|
||||
+
|
||||
+ if (mask & profile->rlimits.mask &&
|
||||
+ profile->rlimits.limits[i].rlim_max < new_rlim.rlim_max) {
|
||||
+ new_rlim.rlim_max = profile->rlimits.limits[i].rlim_max;
|
||||
+ /* soft limit should not exceed hard limit */
|
||||
+ if (new_rlim.rlim_cur > new_rlim.rlim_max)
|
||||
+ new_rlim.rlim_cur = new_rlim.rlim_max;
|
||||
+ }
|
||||
+
|
||||
+ *old_rlim = new_rlim;
|
||||
+ }
|
||||
+ task_unlock(task->group_leader);
|
||||
+}
|
||||
|
||||
/*******************************
|
||||
* Global task related functions
|
||||
@@ -885,6 +961,7 @@ int aa_revalidate_sk(struct sock *sk, ch
|
||||
*/
|
||||
int aa_clone(struct task_struct *child)
|
||||
{
|
||||
+ struct aa_audit sa;
|
||||
struct aa_task_context *cxt, *child_cxt;
|
||||
struct aa_profile *profile;
|
||||
|
||||
@@ -894,6 +971,11 @@ int aa_clone(struct task_struct *child)
|
||||
if (!child_cxt)
|
||||
return -ENOMEM;
|
||||
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = "clone";
|
||||
+ sa.task = child->pid;
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+
|
||||
repeat:
|
||||
profile = aa_get_profile(current);
|
||||
if (profile) {
|
||||
@@ -910,18 +992,22 @@ repeat:
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
+ if (aa_rlimit_nproc(profile)) {
|
||||
+ sa.info = "rlimit nproc limit exceeded";
|
||||
+ unlock_profile(profile);
|
||||
+ aa_audit_reject(profile, &sa);
|
||||
+ aa_put_profile(profile);
|
||||
+ return -EAGAIN;
|
||||
+ }
|
||||
+
|
||||
/* No need to grab the child's task lock here. */
|
||||
aa_change_task_context(child, child_cxt, profile,
|
||||
cxt->cookie, cxt->previous_profile);
|
||||
+
|
||||
unlock_profile(profile);
|
||||
|
||||
if (APPARMOR_COMPLAIN(child_cxt) &&
|
||||
profile == profile->ns->null_complain_profile) {
|
||||
- struct aa_audit sa;
|
||||
- memset(&sa, 0, sizeof(sa));
|
||||
- sa.operation = "clone";
|
||||
- sa.gfp_mask = GFP_KERNEL;
|
||||
- sa.task = child->pid;
|
||||
aa_audit_hint(profile, &sa);
|
||||
}
|
||||
aa_put_profile(profile);
|
||||
@@ -1156,6 +1242,10 @@ repeat:
|
||||
sa.task = current->parent->pid;
|
||||
aa_audit_reject(profile, &sa);
|
||||
}
|
||||
+ if (PTR_ERR(old_profile) == -EAGAIN) {
|
||||
+ sa.info = "rlimit nproc limit exceeded";
|
||||
+ aa_audit_reject(profile, &sa);
|
||||
+ }
|
||||
new_profile = old_profile;
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -1303,6 +1393,12 @@ static int do_change_profile(struct aa_p
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ if ((error = aa_rlimit_nproc(new_profile))) {
|
||||
+ sa->info = "rlimit nproc limit exceeded";
|
||||
+ aa_audit_reject(cxt->profile, sa);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
if (new_profile == ns->null_complain_profile)
|
||||
aa_audit_hint(cxt->profile, sa);
|
||||
|
||||
@@ -1481,17 +1577,18 @@ struct aa_profile *__aa_replace_profile(
|
||||
|
||||
cxt = lock_task_and_profiles(task, profile);
|
||||
if (unlikely(profile && profile->isstale)) {
|
||||
- task_unlock(task);
|
||||
- unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
|
||||
- aa_free_task_context(new_cxt);
|
||||
- return ERR_PTR(-ESTALE);
|
||||
+ old_profile = ERR_PTR(-ESTALE);
|
||||
+ goto error;
|
||||
}
|
||||
|
||||
if ((current->ptrace & PT_PTRACED) && aa_may_ptrace(cxt, profile)) {
|
||||
- task_unlock(task);
|
||||
- unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
|
||||
- aa_free_task_context(new_cxt);
|
||||
- return ERR_PTR(-EPERM);
|
||||
+ old_profile = ERR_PTR(-EPERM);
|
||||
+ goto error;
|
||||
+ }
|
||||
+
|
||||
+ if (aa_rlimit_nproc(profile)) {
|
||||
+ old_profile = ERR_PTR(-EAGAIN);
|
||||
+ goto error;
|
||||
}
|
||||
|
||||
if (cxt)
|
||||
@@ -1499,8 +1596,15 @@ struct aa_profile *__aa_replace_profile(
|
||||
aa_change_task_context(task, new_cxt, profile, 0, NULL);
|
||||
|
||||
task_unlock(task);
|
||||
+ aa_set_rlimits(task, profile);
|
||||
unlock_both_profiles(profile, old_profile);
|
||||
return old_profile;
|
||||
+
|
||||
+error:
|
||||
+ task_unlock(task);
|
||||
+ unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
|
||||
+ aa_free_task_context(new_cxt);
|
||||
+ return old_profile;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1565,6 +1669,7 @@ void aa_change_task_context(struct task_
|
||||
|
||||
if (old_cxt) {
|
||||
list_del_init(&old_cxt->list);
|
||||
+ old_cxt->profile->task_count--;
|
||||
call_rcu(&old_cxt->rcu, free_aa_task_context_rcu_callback);
|
||||
}
|
||||
if (new_cxt) {
|
||||
@@ -1576,6 +1681,7 @@ void aa_change_task_context(struct task_
|
||||
new_cxt->cookie = cookie;
|
||||
new_cxt->task = task;
|
||||
new_cxt->profile = aa_dup_profile(profile);
|
||||
+ profile->task_count++;
|
||||
new_cxt->previous_profile = aa_dup_profile(previous_profile);
|
||||
list_move(&new_cxt->list, &profile->task_contexts);
|
||||
}
|
||||
--- a/security/apparmor/module_interface.c
|
||||
+++ b/security/apparmor/module_interface.c
|
||||
@@ -177,6 +177,22 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int aa_is_u64(struct aa_ext *e, u64 *data, const char *name)
|
||||
+{
|
||||
+ void *pos = e->pos;
|
||||
+ if (aa_is_nameX(e, AA_U64, name)) {
|
||||
+ if (!aa_inbounds(e, sizeof(u64)))
|
||||
+ goto fail;
|
||||
+ if (data)
|
||||
+ *data = le64_to_cpu(get_unaligned((u64 *)e->pos));
|
||||
+ e->pos += sizeof(u64);
|
||||
+ return 1;
|
||||
+ }
|
||||
+fail:
|
||||
+ e->pos = pos;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static size_t aa_is_array(struct aa_ext *e, const char *name)
|
||||
{
|
||||
void *pos = e->pos;
|
||||
@@ -312,6 +328,39 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int aa_unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
|
||||
+{
|
||||
+ void *pos = e->pos;
|
||||
+
|
||||
+ /* rlimits are optional */
|
||||
+ if (aa_is_nameX(e, AA_STRUCT, "rlimits")) {
|
||||
+ int i, size;
|
||||
+ u32 tmp = 0;
|
||||
+ if (!aa_is_u32(e, &tmp, NULL))
|
||||
+ goto fail;
|
||||
+ profile->rlimits.mask = tmp;
|
||||
+
|
||||
+ size = aa_is_array(e, NULL);
|
||||
+ if (size > RLIM_NLIMITS)
|
||||
+ goto fail;
|
||||
+ for (i = 0; i < size; i++) {
|
||||
+ u64 tmp = 0;
|
||||
+ if (!aa_is_u64(e, &tmp, NULL))
|
||||
+ goto fail;
|
||||
+ profile->rlimits.limits[i].rlim_max = tmp;
|
||||
+ }
|
||||
+ if (!aa_is_nameX(e, AA_ARRAYEND, NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ return 1;
|
||||
+
|
||||
+fail:
|
||||
+ e->pos = pos;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* aa_unpack_profile - unpack a serialized profile
|
||||
* @e: serialized data extent information
|
||||
@@ -355,6 +404,9 @@ static struct aa_profile *aa_unpack_prof
|
||||
if (!aa_is_u32(e, &(profile->set_caps), NULL))
|
||||
goto fail;
|
||||
|
||||
+ if (!aa_unpack_rlimits(e, profile))
|
||||
+ goto fail;
|
||||
+
|
||||
size = aa_is_array(e, "net_allowed_af");
|
||||
if (size) {
|
||||
if (size > AF_MAX)
|
||||
@@ -614,6 +666,8 @@ ssize_t aa_replace_profile(void *udata,
|
||||
sa.operation = "profile_load";
|
||||
goto out;
|
||||
}
|
||||
+ /* do not fail replacement based off of profile's NPROC rlimit */
|
||||
+
|
||||
/*
|
||||
* Replacement needs to allocate a new aa_task_context for each
|
||||
* task confined by old_profile. To do this the profile locks
|
||||
@@ -634,6 +688,7 @@ ssize_t aa_replace_profile(void *udata,
|
||||
task_lock(task);
|
||||
task_replace(task, new_cxt, new_profile);
|
||||
task_unlock(task);
|
||||
+ aa_set_rlimits(task, new_profile);
|
||||
new_cxt = NULL;
|
||||
}
|
||||
unlock_both_profiles(old_profile, new_profile);
|
||||
@@ -656,6 +711,7 @@ out:
|
||||
*
|
||||
* remove a profile from the profile list and all aa_task_context references
|
||||
* to said profile.
|
||||
+ * NOTE: removing confinement does not restore rlimits to preconfinemnet values
|
||||
*/
|
||||
ssize_t aa_remove_profile(char *name, size_t size)
|
||||
{
|
||||
@@ -1,60 +0,0 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: Add d_namespace_path() to compute namespace relative pathnames
|
||||
|
||||
In AppArmor, we are interested in pathnames relative to the namespace root.
|
||||
This is the same as d_path() except for the root where the search ends. Add
|
||||
a function for computing the namespace-relative path.
|
||||
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/namespace.c | 30 ++++++++++++++++++++++++++++++
|
||||
include/linux/mount.h | 2 ++
|
||||
2 files changed, 32 insertions(+)
|
||||
|
||||
--- a/fs/namespace.c
|
||||
+++ b/fs/namespace.c
|
||||
@@ -2357,3 +2357,33 @@ void put_mnt_ns(struct mnt_namespace *ns
|
||||
kfree(ns);
|
||||
}
|
||||
EXPORT_SYMBOL(put_mnt_ns);
|
||||
+
|
||||
+char *d_namespace_path(struct dentry *dentry, struct vfsmount *vfsmnt,
|
||||
+ char *buf, int buflen)
|
||||
+{
|
||||
+ struct path root, tmp, ns_root = { };
|
||||
+ struct path path = { .mnt = vfsmnt, .dentry = dentry };
|
||||
+ char *res;
|
||||
+
|
||||
+ read_lock(¤t->fs->lock);
|
||||
+ root = current->fs->root;
|
||||
+ path_get(¤t->fs->root);
|
||||
+ read_unlock(¤t->fs->lock);
|
||||
+ spin_lock(&vfsmount_lock);
|
||||
+ if (root.mnt)
|
||||
+ ns_root.mnt = mntget(root.mnt->mnt_ns->root);
|
||||
+ if (ns_root.mnt)
|
||||
+ ns_root.dentry = dget(ns_root.mnt->mnt_root);
|
||||
+ spin_unlock(&vfsmount_lock);
|
||||
+ tmp = ns_root;
|
||||
+ res = __d_path(&path, &tmp, buf, buflen,
|
||||
+ D_PATH_FAIL_DELETED | D_PATH_DISCONNECT);
|
||||
+ path_put(&root);
|
||||
+ path_put(&ns_root);
|
||||
+
|
||||
+ /* Prevent empty path for lazily unmounted filesystems. */
|
||||
+ if (!IS_ERR(res) && *res == '\0')
|
||||
+ *--res = '.';
|
||||
+ return res;
|
||||
+}
|
||||
+EXPORT_SYMBOL(d_namespace_path);
|
||||
--- a/include/linux/mount.h
|
||||
+++ b/include/linux/mount.h
|
||||
@@ -137,4 +137,6 @@ extern void mark_mounts_for_expiry(struc
|
||||
extern spinlock_t vfsmount_lock;
|
||||
extern dev_t name_to_dev_t(char *name);
|
||||
|
||||
+extern char *d_namespace_path(struct dentry *, struct vfsmount *, char *, int);
|
||||
+
|
||||
#endif /* _LINUX_MOUNT_H */
|
||||
@@ -1,25 +0,0 @@
|
||||
From: Miklos Szeredi <mszeredi@suse.cz>
|
||||
Subject: fix oops in d_namespace_path
|
||||
Patch-mainline: no
|
||||
References: bnc#433504
|
||||
|
||||
d_namespace_path uses the current->fs->root to get the current
|
||||
namespace. If root is detached root.mnt->mnt_ns will be NULL, causing
|
||||
an Oops. Fix by checking this before dereferencing the mnt_ns.
|
||||
|
||||
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
|
||||
---
|
||||
fs/namespace.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/fs/namespace.c
|
||||
+++ b/fs/namespace.c
|
||||
@@ -2370,7 +2370,7 @@ char *d_namespace_path(struct dentry *de
|
||||
path_get(¤t->fs->root);
|
||||
read_unlock(¤t->fs->lock);
|
||||
spin_lock(&vfsmount_lock);
|
||||
- if (root.mnt)
|
||||
+ if (root.mnt && root.mnt->mnt_ns)
|
||||
ns_root.mnt = mntget(root.mnt->mnt_ns->root);
|
||||
if (ns_root.mnt)
|
||||
ns_root.dentry = dget(ns_root.mnt->mnt_root);
|
||||
@@ -1,42 +0,0 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: Switch to vfs_permission() in do_path_lookup()
|
||||
|
||||
Switch from file_permission() to vfs_permission() in do_path_lookup():
|
||||
this avoids calling permission() with a NULL nameidata here.
|
||||
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/namei.c | 7 ++-----
|
||||
1 file changed, 2 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -1085,24 +1085,21 @@ static int do_path_lookup(int dfd, const
|
||||
path_get(&fs->pwd);
|
||||
read_unlock(&fs->lock);
|
||||
} else {
|
||||
- struct dentry *dentry;
|
||||
-
|
||||
file = fget_light(dfd, &fput_needed);
|
||||
retval = -EBADF;
|
||||
if (!file)
|
||||
goto out_fail;
|
||||
|
||||
- dentry = file->f_path.dentry;
|
||||
+ nd->path = file->f_path;
|
||||
|
||||
retval = -ENOTDIR;
|
||||
- if (!S_ISDIR(dentry->d_inode->i_mode))
|
||||
+ if (!S_ISDIR(nd->path.dentry->d_inode->i_mode))
|
||||
goto fput_fail;
|
||||
|
||||
retval = file_permission(file, MAY_EXEC);
|
||||
if (retval)
|
||||
goto fput_fail;
|
||||
|
||||
- nd->path = file->f_path;
|
||||
path_get(&file->f_path);
|
||||
|
||||
fput_light(file, fput_needed);
|
||||
@@ -1,26 +0,0 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: [PATCH] LSM: Export security_inode_permission for aufs
|
||||
Patch-mainline: Never
|
||||
References: 356902
|
||||
|
||||
In order for aufs to work with AppArmor, it needs to be able to call
|
||||
security_inode_permission itself.
|
||||
|
||||
This patch is a _workaround_ since the author will need to find a
|
||||
mainline-compatible solution moving forward.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
security/security.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -412,6 +412,7 @@ int security_inode_mknod(struct inode *d
|
||||
return 0;
|
||||
return security_ops->inode_mknod(dir, dentry, mnt, mode, dev);
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(security_inode_permission);
|
||||
|
||||
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct vfsmount *old_mnt, struct inode *new_dir,
|
||||
@@ -1,84 +0,0 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: Enable LSM hooks to distinguish operations on file descriptors from operations on pathnames
|
||||
|
||||
Struct iattr already contains ia_file since commit cc4e69de from
|
||||
Miklos (which is related to commit befc649c). Use this to pass
|
||||
struct file down the setattr hooks. This allows LSMs to distinguish
|
||||
operations on file descriptors from operations on paths.
|
||||
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
Cc: Miklos Szeredi <mszeredi@suse.cz>
|
||||
|
||||
---
|
||||
fs/nfsd/vfs.c | 12 +++++++-----
|
||||
fs/open.c | 5 ++++-
|
||||
2 files changed, 11 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -425,7 +425,7 @@ static ssize_t nfsd_getxattr(struct dent
|
||||
{
|
||||
ssize_t buflen;
|
||||
|
||||
- buflen = vfs_getxattr(dentry, mnt, key, NULL, 0);
|
||||
+ buflen = vfs_getxattr(dentry, mnt, key, NULL, 0, NULL);
|
||||
if (buflen <= 0)
|
||||
return buflen;
|
||||
|
||||
@@ -433,7 +433,7 @@ static ssize_t nfsd_getxattr(struct dent
|
||||
if (!*buf)
|
||||
return -ENOMEM;
|
||||
|
||||
- return vfs_getxattr(dentry, mnt, key, *buf, buflen);
|
||||
+ return vfs_getxattr(dentry, mnt, key, *buf, buflen, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -459,7 +459,7 @@ set_nfsv4_acl_one(struct dentry *dentry,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- error = vfs_setxattr(dentry, mnt, key, buf, len, 0);
|
||||
+ error = vfs_setxattr(dentry, mnt, key, buf, len, 0, NULL);
|
||||
out:
|
||||
kfree(buf);
|
||||
return error;
|
||||
@@ -2133,12 +2133,14 @@ nfsd_set_posix_acl(struct svc_fh *fhp, i
|
||||
if (error)
|
||||
goto getout;
|
||||
if (size)
|
||||
- error = vfs_setxattr(fhp->fh_dentry, mnt, name, value, size,0);
|
||||
+ error = vfs_setxattr(fhp->fh_dentry, mnt, name, value, size, 0,
|
||||
+ NULL);
|
||||
else {
|
||||
if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
|
||||
error = 0;
|
||||
else {
|
||||
- error = vfs_removexattr(fhp->fh_dentry, mnt, name);
|
||||
+ error = vfs_removexattr(fhp->fh_dentry, mnt, name,
|
||||
+ NULL);
|
||||
if (error == -ENODATA)
|
||||
error = 0;
|
||||
}
|
||||
--- a/fs/open.c
|
||||
+++ b/fs/open.c
|
||||
@@ -623,7 +623,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd
|
||||
if (mode == (mode_t) -1)
|
||||
mode = inode->i_mode;
|
||||
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
|
||||
- newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||
+ newattrs.ia_valid = ATTR_MODE | ATTR_CTIME | ATTR_FILE;
|
||||
err = fnotify_change(dentry, file->f_path.mnt, &newattrs, file);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
mnt_drop_write(file->f_path.mnt);
|
||||
@@ -686,6 +686,9 @@ static int chown_common(struct dentry *
|
||||
if (!S_ISDIR(inode->i_mode))
|
||||
newattrs.ia_valid |=
|
||||
ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
|
||||
+ if (file)
|
||||
+ newattrs.ia_valid |= ATTR_FILE;
|
||||
+
|
||||
mutex_lock(&inode->i_mutex);
|
||||
error = fnotify_change(dentry, mnt, &newattrs, file);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
@@ -1,26 +0,0 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: fix enforcement of deny rules in complain mode
|
||||
Patch-mainline: no
|
||||
References: bnc#426159
|
||||
|
||||
Fix enforcement of deny rules so that they are not enforced in complain
|
||||
mode. This is necessary so that application behavior is not changed by
|
||||
the presence of the deny rule.
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/main.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -325,7 +325,7 @@ static int aa_audit_file(struct aa_profi
|
||||
} else {
|
||||
int mask = AUDIT_QUIET_MASK(sa->audit_mask);
|
||||
|
||||
- if (!(sa->denied_mask & ~mask))
|
||||
+ if (!(sa->denied_mask & ~mask) && !PROFILE_COMPLAIN(profile))
|
||||
return sa->error_code;
|
||||
|
||||
/* mask off perms whose denial is being silenced */
|
||||
@@ -1,25 +0,0 @@
|
||||
From: John Johansen <jrjohansen@verizon.net>
|
||||
Subject: [PATCH] AppArmor: Fix leak of filename for deleted files
|
||||
|
||||
This patch fixes a memory leak where the name doesn't get freed when
|
||||
a file has been deleted.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
security/apparmor/main.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -500,10 +500,10 @@ static char *aa_get_name(struct dentry *
|
||||
*buffer = buf;
|
||||
return name;
|
||||
}
|
||||
+ kfree(buf);
|
||||
if (PTR_ERR(name) != -ENAMETOOLONG)
|
||||
return name;
|
||||
|
||||
- kfree(buf);
|
||||
size <<= 1;
|
||||
if (size > apparmor_path_max)
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
@@ -1,66 +0,0 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: fix recognition of security= boot parameter
|
||||
Patch-mainline: no
|
||||
References: bnc#442668
|
||||
|
||||
Fix AppArmor to respect the kernel boot parameter security=, so that if a
|
||||
different lsm is choosen apparmor does not try to register its lsm hooks.
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
security/Kconfig | 9 +++++++++
|
||||
security/apparmor/lsm.c | 5 +++--
|
||||
security/security.c | 2 +-
|
||||
3 files changed, 13 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/security/Kconfig
|
||||
+++ b/security/Kconfig
|
||||
@@ -51,6 +51,15 @@ config SECURITY
|
||||
|
||||
If you are unsure how to answer this question, answer N.
|
||||
|
||||
+config SECURITY_DEFAULT
|
||||
+ string "Default security module"
|
||||
+ depends on SECURITY
|
||||
+ default ""
|
||||
+ help
|
||||
+ This determines the security module used if the security=
|
||||
+ boot parmater is not provided. If a security module is not
|
||||
+ specified the first module to register will be used.
|
||||
+
|
||||
config SECURITY_NETWORK
|
||||
bool "Socket and Networking Security Hooks"
|
||||
depends on SECURITY
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -911,6 +911,7 @@ static int apparmor_task_setrlimit(unsig
|
||||
}
|
||||
|
||||
struct security_operations apparmor_ops = {
|
||||
+ .name = "apparmor",
|
||||
.ptrace_may_access = apparmor_ptrace_may_access,
|
||||
.ptrace_traceme = apparmor_ptrace_traceme,
|
||||
.capget = cap_capget,
|
||||
@@ -989,8 +990,8 @@ static int __init apparmor_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
- if (!apparmor_enabled) {
|
||||
- info_message("AppArmor disabled by boottime parameter\n");
|
||||
+ if (!apparmor_enabled || !security_module_enable(&apparmor_ops)) {
|
||||
+ info_message("AppArmor disabled by boot time parameter\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <linux/security.h>
|
||||
|
||||
/* Boot-time LSM user choice */
|
||||
-static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1];
|
||||
+static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = CONFIG_SECURITY_DEFAULT;
|
||||
|
||||
/* things that live in capability.c */
|
||||
extern struct security_operations default_security_ops;
|
||||
@@ -1,44 +0,0 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: Call lsm hook before unhashing dentry in vfs_rmdir()
|
||||
|
||||
If we unhash the dentry before calling the security_inode_rmdir hook,
|
||||
we cannot compute the file's pathname in the hook anymore. AppArmor
|
||||
needs to know the filename in order to decide whether a file may be
|
||||
deleted, though.
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
fs/namei.c | 13 +++++++------
|
||||
1 file changed, 7 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2177,6 +2177,10 @@ int vfs_rmdir(struct inode *dir, struct
|
||||
if (!dir->i_op || !dir->i_op->rmdir)
|
||||
return -EPERM;
|
||||
|
||||
+ error = security_inode_rmdir(dir, dentry, mnt);
|
||||
+ if (error)
|
||||
+ return error;
|
||||
+
|
||||
DQUOT_INIT(dir);
|
||||
|
||||
mutex_lock(&dentry->d_inode->i_mutex);
|
||||
@@ -2184,12 +2188,9 @@ int vfs_rmdir(struct inode *dir, struct
|
||||
if (d_mountpoint(dentry))
|
||||
error = -EBUSY;
|
||||
else {
|
||||
- error = security_inode_rmdir(dir, dentry, mnt);
|
||||
- if (!error) {
|
||||
- error = dir->i_op->rmdir(dir, dentry);
|
||||
- if (!error)
|
||||
- dentry->d_inode->i_flags |= S_DEAD;
|
||||
- }
|
||||
+ error = dir->i_op->rmdir(dir, dentry);
|
||||
+ if (!error)
|
||||
+ dentry->d_inode->i_flags |= S_DEAD;
|
||||
}
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
if (!error) {
|
||||
@@ -1,108 +0,0 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: fix log messages to enable tools profile learning
|
||||
Patch-mainline: no
|
||||
References: bnc#447564
|
||||
|
||||
The allocation of the child pid is done after the LSM clone hook, which
|
||||
breaks the AppArmor tools fork tracking, for profiles learning. Output
|
||||
the parent pid with each log message to enable the tools to handle fork
|
||||
tracking.
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/lsm.c | 28 ----------------------------
|
||||
security/apparmor/main.c | 10 +++++-----
|
||||
security/apparmor/module_interface.c | 2 +-
|
||||
3 files changed, 6 insertions(+), 34 deletions(-)
|
||||
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -143,20 +143,6 @@ static int param_set_aa_enabled(const ch
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int aa_reject_syscall(struct task_struct *task, gfp_t flags,
|
||||
- const char *name)
|
||||
-{
|
||||
- struct aa_profile *profile = aa_get_profile(task);
|
||||
- int error = 0;
|
||||
-
|
||||
- if (profile) {
|
||||
- error = aa_audit_syscallreject(profile, flags, name);
|
||||
- aa_put_profile(profile);
|
||||
- }
|
||||
-
|
||||
- return error;
|
||||
-}
|
||||
-
|
||||
static int apparmor_ptrace(struct task_struct *parent,
|
||||
struct task_struct *child)
|
||||
{
|
||||
@@ -292,17 +278,6 @@ static int apparmor_bprm_secureexec(stru
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int apparmor_sb_mount(char *dev_name, struct path *path, char *type,
|
||||
- unsigned long flags, void *data)
|
||||
-{
|
||||
- return aa_reject_syscall(current, GFP_KERNEL, "mount");
|
||||
-}
|
||||
-
|
||||
-static int apparmor_umount(struct vfsmount *mnt, int flags)
|
||||
-{
|
||||
- return aa_reject_syscall(current, GFP_KERNEL, "umount");
|
||||
-}
|
||||
-
|
||||
static int apparmor_inode_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, int mask)
|
||||
{
|
||||
@@ -925,9 +900,6 @@ struct security_operations apparmor_ops
|
||||
.bprm_set_security = apparmor_bprm_set_security,
|
||||
.bprm_secureexec = apparmor_bprm_secureexec,
|
||||
|
||||
- .sb_mount = apparmor_sb_mount,
|
||||
- .sb_umount = apparmor_umount,
|
||||
-
|
||||
.inode_mkdir = apparmor_inode_mkdir,
|
||||
.inode_rmdir = apparmor_inode_rmdir,
|
||||
.inode_create = apparmor_inode_create,
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -229,9 +229,13 @@ static int aa_audit_base(struct aa_profi
|
||||
audit_log_format(ab, " protocol=%d", sa->protocol);
|
||||
}
|
||||
|
||||
- audit_log_format(ab, " pid=%d", current->pid);
|
||||
+ audit_log_format(ab, " pid=%d", current->pid);
|
||||
|
||||
if (profile) {
|
||||
+ if (!sa->parent)
|
||||
+ audit_log_format(ab, " parent=%d",
|
||||
+ current->real_parent->pid);
|
||||
+
|
||||
audit_log_format(ab, " profile=");
|
||||
audit_log_untrustedstring(ab, profile->name);
|
||||
|
||||
@@ -1006,10 +1010,6 @@ repeat:
|
||||
|
||||
unlock_profile(profile);
|
||||
|
||||
- if (APPARMOR_COMPLAIN(child_cxt) &&
|
||||
- profile == profile->ns->null_complain_profile) {
|
||||
- aa_audit_hint(profile, &sa);
|
||||
- }
|
||||
aa_put_profile(profile);
|
||||
} else
|
||||
aa_free_task_context(child_cxt);
|
||||
--- a/security/apparmor/module_interface.c
|
||||
+++ b/security/apparmor/module_interface.c
|
||||
@@ -126,7 +126,7 @@ static int aa_is_nameX(struct aa_ext *e,
|
||||
* AA_NAME tag value is a u16.
|
||||
*/
|
||||
if (aa_is_X(e, AA_NAME)) {
|
||||
- char *tag;
|
||||
+ char *tag = NULL;
|
||||
size_t size = aa_is_u16_chunk(e, &tag);
|
||||
/* if a name is specified it must match. otherwise skip tag */
|
||||
if (name && (!size || strcmp(name, tag)))
|
||||
@@ -1,28 +0,0 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: AppArmor: reintroduce ATTR_FILE
|
||||
|
||||
The fsetattr patch removed ATTR_FILE but AppArmor needs it to distinguish
|
||||
file based writes.
|
||||
|
||||
Note: Now that LSMs must be static, it would be better to add a file
|
||||
pointer argument to security_operations->inode_setattr() instead. Then
|
||||
move the fs.h chunk to patches.apparmor/fsetattr-restore-ia_file. -jeffm
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/open.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/fs/open.c
|
||||
+++ b/fs/open.c
|
||||
@@ -208,6 +208,9 @@ int do_truncate(struct dentry *dentry, s
|
||||
newattrs.ia_size = length;
|
||||
newattrs.ia_valid = ATTR_SIZE | time_attrs;
|
||||
|
||||
+ if (filp)
|
||||
+ newattrs.ia_valid |= ATTR_FILE;
|
||||
+
|
||||
/* Remove suid/sgid on truncate too */
|
||||
newattrs.ia_valid |= should_remove_suid(dentry);
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: [PATCH] vfs: restore ia_file for compatibility with external modules
|
||||
References: bnc#381259
|
||||
|
||||
patches.apparmor/fsetattr.diff eliminated ia_file and ATTR_FILE in favor
|
||||
of providing a ->fsetattr call that used a file pointer. Until this
|
||||
patch is accepted into mainline, this patch provides the backward
|
||||
compatibility for external file system modules.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
fs/attr.c | 13 ++++++++++++-
|
||||
include/linux/fs.h | 11 +++++++++++
|
||||
2 files changed, 23 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/fs/attr.c
|
||||
+++ b/fs/attr.c
|
||||
@@ -168,8 +168,19 @@ int fnotify_change(struct dentry *dentry
|
||||
if (!error) {
|
||||
if (file && file->f_op && file->f_op->fsetattr)
|
||||
error = file->f_op->fsetattr(file, attr);
|
||||
- else
|
||||
+ else {
|
||||
+ /* External file system still expect to be
|
||||
+ * passed a file pointer via ia_file and
|
||||
+ * have it announced via ATTR_FILE. This
|
||||
+ * just makes it so they don't need to
|
||||
+ * change their API just for us. External
|
||||
+ * callers will have set these themselves. */
|
||||
+ if (file) {
|
||||
+ attr->ia_valid |= ATTR_FILE;
|
||||
+ attr->ia_file = file;
|
||||
+ }
|
||||
error = inode->i_op->setattr(dentry, attr);
|
||||
+ }
|
||||
}
|
||||
} else {
|
||||
error = inode_change_ok(inode, attr);
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -367,6 +367,17 @@ struct iattr {
|
||||
struct timespec ia_atime;
|
||||
struct timespec ia_mtime;
|
||||
struct timespec ia_ctime;
|
||||
+
|
||||
+ /*
|
||||
+ * Not an attribute, but an auxilary info for filesystems wanting to
|
||||
+ * implement an ftruncate() like method. NOTE: filesystem should
|
||||
+ * check for (ia_valid & ATTR_FILE), and not for (ia_file != NULL).
|
||||
+ *
|
||||
+ * NOTE: With patches.apparmor/fsetattr.diff applied, this is
|
||||
+ * for compatibility with external file system modules only. There
|
||||
+ * should not be any in-kernel users left.
|
||||
+ */
|
||||
+ struct file *ia_file;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1,414 +0,0 @@
|
||||
Subject: VFS: new fsetattr() file operation
|
||||
|
||||
From: Miklos Szeredi <mszeredi@suse.cz>
|
||||
|
||||
Add a new file operation: f_op->fsetattr(), that is invoked by
|
||||
ftruncate, fchmod, fchown and utimensat. Fall back to i_op->setattr()
|
||||
if it is not defined.
|
||||
|
||||
For the reasons why we need this, see patch adding fgetattr().
|
||||
|
||||
ftruncate() already passed the open file to the filesystem via the
|
||||
ia_file member of struct iattr. However it is cleaner to have a
|
||||
separate file operation for this, so remove ia_file, ATTR_FILE and
|
||||
convert existing users: fuse and AFS.
|
||||
|
||||
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> ---
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de> ---
|
||||
|
||||
---
|
||||
fs/afs/dir.c | 1 +
|
||||
fs/afs/file.c | 1 +
|
||||
fs/afs/inode.c | 19 +++++++++++++++----
|
||||
fs/afs/internal.h | 1 +
|
||||
fs/attr.c | 19 +++++++++++++++----
|
||||
fs/fuse/dir.c | 20 +++++++++-----------
|
||||
fs/fuse/file.c | 7 +++++++
|
||||
fs/fuse/fuse_i.h | 4 ++++
|
||||
fs/open.c | 20 ++++++++------------
|
||||
fs/utimes.c | 9 +++++----
|
||||
include/linux/fs.h | 9 ++-------
|
||||
11 files changed, 68 insertions(+), 42 deletions(-)
|
||||
|
||||
--- a/fs/afs/dir.c
|
||||
+++ b/fs/afs/dir.c
|
||||
@@ -45,6 +45,7 @@ const struct file_operations afs_dir_fil
|
||||
.release = afs_release,
|
||||
.readdir = afs_readdir,
|
||||
.lock = afs_lock,
|
||||
+ .fsetattr = afs_fsetattr,
|
||||
};
|
||||
|
||||
const struct inode_operations afs_dir_inode_operations = {
|
||||
--- a/fs/afs/file.c
|
||||
+++ b/fs/afs/file.c
|
||||
@@ -36,6 +36,7 @@ const struct file_operations afs_file_op
|
||||
.fsync = afs_fsync,
|
||||
.lock = afs_lock,
|
||||
.flock = afs_flock,
|
||||
+ .fsetattr = afs_fsetattr,
|
||||
};
|
||||
|
||||
const struct inode_operations afs_file_inode_operations = {
|
||||
--- a/fs/afs/inode.c
|
||||
+++ b/fs/afs/inode.c
|
||||
@@ -358,7 +358,8 @@ void afs_clear_inode(struct inode *inode
|
||||
/*
|
||||
* set the attributes of an inode
|
||||
*/
|
||||
-int afs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
+static int afs_do_setattr(struct dentry *dentry, struct iattr *attr,
|
||||
+ struct file *file)
|
||||
{
|
||||
struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
|
||||
struct key *key;
|
||||
@@ -380,8 +381,8 @@ int afs_setattr(struct dentry *dentry, s
|
||||
afs_writeback_all(vnode);
|
||||
}
|
||||
|
||||
- if (attr->ia_valid & ATTR_FILE) {
|
||||
- key = attr->ia_file->private_data;
|
||||
+ if (file) {
|
||||
+ key = file->private_data;
|
||||
} else {
|
||||
key = afs_request_key(vnode->volume->cell);
|
||||
if (IS_ERR(key)) {
|
||||
@@ -391,10 +392,20 @@ int afs_setattr(struct dentry *dentry, s
|
||||
}
|
||||
|
||||
ret = afs_vnode_setattr(vnode, key, attr);
|
||||
- if (!(attr->ia_valid & ATTR_FILE))
|
||||
+ if (!file)
|
||||
key_put(key);
|
||||
|
||||
error:
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
+
|
||||
+int afs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
+{
|
||||
+ return afs_do_setattr(dentry, attr, NULL);
|
||||
+}
|
||||
+
|
||||
+int afs_fsetattr(struct file *file, struct iattr *attr)
|
||||
+{
|
||||
+ return afs_do_setattr(file->f_path.dentry, attr, file);
|
||||
+}
|
||||
--- a/fs/afs/internal.h
|
||||
+++ b/fs/afs/internal.h
|
||||
@@ -548,6 +548,7 @@ extern void afs_zap_data(struct afs_vnod
|
||||
extern int afs_validate(struct afs_vnode *, struct key *);
|
||||
extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
|
||||
extern int afs_setattr(struct dentry *, struct iattr *);
|
||||
+extern int afs_fsetattr(struct file *, struct iattr *);
|
||||
extern void afs_clear_inode(struct inode *);
|
||||
|
||||
/*
|
||||
--- a/fs/attr.c
|
||||
+++ b/fs/attr.c
|
||||
@@ -100,8 +100,8 @@ int inode_setattr(struct inode * inode,
|
||||
}
|
||||
EXPORT_SYMBOL(inode_setattr);
|
||||
|
||||
-int notify_change(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- struct iattr *attr)
|
||||
+int fnotify_change(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct iattr *attr, struct file *file)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
mode_t mode = inode->i_mode;
|
||||
@@ -165,8 +165,12 @@ int notify_change(struct dentry *dentry,
|
||||
|
||||
if (inode->i_op && inode->i_op->setattr) {
|
||||
error = security_inode_setattr(dentry, mnt, attr);
|
||||
- if (!error)
|
||||
- error = inode->i_op->setattr(dentry, attr);
|
||||
+ if (!error) {
|
||||
+ if (file && file->f_op && file->f_op->fsetattr)
|
||||
+ error = file->f_op->fsetattr(file, attr);
|
||||
+ else
|
||||
+ error = inode->i_op->setattr(dentry, attr);
|
||||
+ }
|
||||
} else {
|
||||
error = inode_change_ok(inode, attr);
|
||||
if (!error)
|
||||
@@ -188,5 +192,12 @@ int notify_change(struct dentry *dentry,
|
||||
|
||||
return error;
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(fnotify_change);
|
||||
+
|
||||
+int notify_change(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct iattr *attr)
|
||||
+{
|
||||
+ return fnotify_change(dentry, mnt, attr, NULL);
|
||||
+}
|
||||
|
||||
EXPORT_SYMBOL(notify_change);
|
||||
--- a/fs/fuse/dir.c
|
||||
+++ b/fs/fuse/dir.c
|
||||
@@ -1105,21 +1105,22 @@ static int fuse_dir_fsync(struct file *f
|
||||
return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
|
||||
}
|
||||
|
||||
-static bool update_mtime(unsigned ivalid)
|
||||
+static bool update_mtime(unsigned ivalid, bool have_file)
|
||||
{
|
||||
/* Always update if mtime is explicitly set */
|
||||
if (ivalid & ATTR_MTIME_SET)
|
||||
return true;
|
||||
|
||||
/* If it's an open(O_TRUNC) or an ftruncate(), don't update */
|
||||
- if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE)))
|
||||
+ if ((ivalid & ATTR_SIZE) && ((ivalid & ATTR_OPEN) || have_file))
|
||||
return false;
|
||||
|
||||
/* In all other cases update */
|
||||
return true;
|
||||
}
|
||||
|
||||
-static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
|
||||
+static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
|
||||
+ bool have_file)
|
||||
{
|
||||
unsigned ivalid = iattr->ia_valid;
|
||||
|
||||
@@ -1138,7 +1139,7 @@ static void iattr_to_fattr(struct iattr
|
||||
if (!(ivalid & ATTR_ATIME_SET))
|
||||
arg->valid |= FATTR_ATIME_NOW;
|
||||
}
|
||||
- if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) {
|
||||
+ if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, have_file)) {
|
||||
arg->valid |= FATTR_MTIME;
|
||||
arg->mtime = iattr->ia_mtime.tv_sec;
|
||||
arg->mtimensec = iattr->ia_mtime.tv_nsec;
|
||||
@@ -1199,8 +1200,8 @@ void fuse_release_nowrite(struct inode *
|
||||
* vmtruncate() doesn't allow for this case, so do the rlimit checking
|
||||
* and the actual truncation by hand.
|
||||
*/
|
||||
-static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
|
||||
- struct file *file)
|
||||
+int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
|
||||
+ struct file *file)
|
||||
{
|
||||
struct inode *inode = entry->d_inode;
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
@@ -1244,7 +1245,7 @@ static int fuse_do_setattr(struct dentry
|
||||
|
||||
memset(&inarg, 0, sizeof(inarg));
|
||||
memset(&outarg, 0, sizeof(outarg));
|
||||
- iattr_to_fattr(attr, &inarg);
|
||||
+ iattr_to_fattr(attr, &inarg, file != NULL);
|
||||
if (file) {
|
||||
struct fuse_file *ff = file->private_data;
|
||||
inarg.valid |= FATTR_FH;
|
||||
@@ -1314,10 +1315,7 @@ error:
|
||||
|
||||
static int fuse_setattr(struct dentry *entry, struct iattr *attr)
|
||||
{
|
||||
- if (attr->ia_valid & ATTR_FILE)
|
||||
- return fuse_do_setattr(entry, attr, attr->ia_file);
|
||||
- else
|
||||
- return fuse_do_setattr(entry, attr, NULL);
|
||||
+ return fuse_do_setattr(entry, attr, NULL);
|
||||
}
|
||||
|
||||
static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
|
||||
--- a/fs/fuse/file.c
|
||||
+++ b/fs/fuse/file.c
|
||||
@@ -1467,6 +1467,11 @@ static loff_t fuse_file_llseek(struct fi
|
||||
return retval;
|
||||
}
|
||||
|
||||
+static int fuse_fsetattr(struct file *file, struct iattr *attr)
|
||||
+{
|
||||
+ return fuse_do_setattr(file->f_path.dentry, attr, file);
|
||||
+}
|
||||
+
|
||||
static const struct file_operations fuse_file_operations = {
|
||||
.llseek = fuse_file_llseek,
|
||||
.read = do_sync_read,
|
||||
@@ -1480,6 +1485,7 @@ static const struct file_operations fuse
|
||||
.fsync = fuse_fsync,
|
||||
.lock = fuse_file_lock,
|
||||
.flock = fuse_file_flock,
|
||||
+ .fsetattr = fuse_fsetattr,
|
||||
.splice_read = generic_file_splice_read,
|
||||
};
|
||||
|
||||
@@ -1493,6 +1499,7 @@ static const struct file_operations fuse
|
||||
.fsync = fuse_fsync,
|
||||
.lock = fuse_file_lock,
|
||||
.flock = fuse_file_flock,
|
||||
+ .fsetattr = fuse_fsetattr,
|
||||
/* no mmap and splice_read */
|
||||
};
|
||||
|
||||
--- a/fs/fuse/fuse_i.h
|
||||
+++ b/fs/fuse/fuse_i.h
|
||||
@@ -551,6 +551,10 @@ void fuse_truncate(struct address_space
|
||||
*/
|
||||
int fuse_dev_init(void);
|
||||
|
||||
+
|
||||
+int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
|
||||
+ struct file *file);
|
||||
+
|
||||
/**
|
||||
* Cleanup the client device
|
||||
*/
|
||||
--- a/fs/open.c
|
||||
+++ b/fs/open.c
|
||||
@@ -207,16 +207,12 @@ int do_truncate(struct dentry *dentry, s
|
||||
|
||||
newattrs.ia_size = length;
|
||||
newattrs.ia_valid = ATTR_SIZE | time_attrs;
|
||||
- if (filp) {
|
||||
- newattrs.ia_file = filp;
|
||||
- newattrs.ia_valid |= ATTR_FILE;
|
||||
- }
|
||||
|
||||
/* Remove suid/sgid on truncate too */
|
||||
newattrs.ia_valid |= should_remove_suid(dentry);
|
||||
|
||||
mutex_lock(&dentry->d_inode->i_mutex);
|
||||
- err = notify_change(dentry, mnt, &newattrs);
|
||||
+ err = fnotify_change(dentry, mnt, &newattrs, filp);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
return err;
|
||||
}
|
||||
@@ -625,7 +621,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd
|
||||
mode = inode->i_mode;
|
||||
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
|
||||
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||
- err = notify_change(dentry, file->f_path.mnt, &newattrs);
|
||||
+ err = fnotify_change(dentry, file->f_path.mnt, &newattrs, file);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
mnt_drop_write(file->f_path.mnt);
|
||||
out_putf:
|
||||
@@ -669,7 +665,7 @@ SYSCALL_DEFINE2(chmod, const char __user
|
||||
}
|
||||
|
||||
static int chown_common(struct dentry * dentry, struct vfsmount *mnt,
|
||||
- uid_t user, gid_t group)
|
||||
+ uid_t user, gid_t group, struct file *file)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -688,7 +684,7 @@ static int chown_common(struct dentry *
|
||||
newattrs.ia_valid |=
|
||||
ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
|
||||
mutex_lock(&inode->i_mutex);
|
||||
- error = notify_change(dentry, mnt, &newattrs);
|
||||
+ error = fnotify_change(dentry, mnt, &newattrs, file);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
return error;
|
||||
@@ -705,7 +701,7 @@ SYSCALL_DEFINE3(chown, const char __user
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
- error = chown_common(path.dentry, path.mnt, user, group);
|
||||
+ error = chown_common(path.dentry, path.mnt, user, group, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
@@ -730,7 +726,7 @@ SYSCALL_DEFINE5(fchownat, int, dfd, cons
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
- error = chown_common(path.dentry, path.mnt, user, group);
|
||||
+ error = chown_common(path.dentry, path.mnt, user, group, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
@@ -749,7 +745,7 @@ SYSCALL_DEFINE3(lchown, const char __use
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
- error = chown_common(path.dentry, path.mnt, user, group);
|
||||
+ error = chown_common(path.dentry, path.mnt, user, group, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
@@ -772,7 +768,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd
|
||||
goto out_fput;
|
||||
dentry = file->f_path.dentry;
|
||||
audit_inode(NULL, dentry);
|
||||
- error = chown_common(dentry, file->f_path.mnt, user, group);
|
||||
+ error = chown_common(dentry, file->f_path.mnt, user, group, file);
|
||||
mnt_drop_write(file->f_path.mnt);
|
||||
out_fput:
|
||||
fput(file);
|
||||
--- a/fs/utimes.c
|
||||
+++ b/fs/utimes.c
|
||||
@@ -48,7 +48,8 @@ static bool nsec_valid(long nsec)
|
||||
return nsec >= 0 && nsec <= 999999999;
|
||||
}
|
||||
|
||||
-static int utimes_common(struct path *path, struct timespec *times)
|
||||
+static int utimes_common(struct path *path, struct timespec *times,
|
||||
+ struct file *f)
|
||||
{
|
||||
int error;
|
||||
struct iattr newattrs;
|
||||
@@ -102,7 +103,7 @@ static int utimes_common(struct path *pa
|
||||
}
|
||||
}
|
||||
mutex_lock(&inode->i_mutex);
|
||||
- error = notify_change(path->dentry, path->mnt, &newattrs);
|
||||
+ error = fnotify_change(path->dentry, path->mnt, &newattrs, f);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
mnt_drop_write_and_out:
|
||||
@@ -149,7 +150,7 @@ long do_utimes(int dfd, char __user *fil
|
||||
if (!file)
|
||||
goto out;
|
||||
|
||||
- error = utimes_common(&file->f_path, times);
|
||||
+ error = utimes_common(&file->f_path, times, file);
|
||||
fput(file);
|
||||
} else {
|
||||
struct path path;
|
||||
@@ -162,7 +163,7 @@ long do_utimes(int dfd, char __user *fil
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
- error = utimes_common(&path, times);
|
||||
+ error = utimes_common(&path, times, NULL);
|
||||
path_put(&path);
|
||||
}
|
||||
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -367,13 +367,6 @@ struct iattr {
|
||||
struct timespec ia_atime;
|
||||
struct timespec ia_mtime;
|
||||
struct timespec ia_ctime;
|
||||
-
|
||||
- /*
|
||||
- * Not an attribute, but an auxilary info for filesystems wanting to
|
||||
- * implement an ftruncate() like method. NOTE: filesystem should
|
||||
- * check for (ia_valid & ATTR_FILE), and not for (ia_file != NULL).
|
||||
- */
|
||||
- struct file *ia_file;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1280,6 +1273,7 @@ struct file_operations {
|
||||
#define HAVE_FOP_OPEN_EXEC
|
||||
int (*open_exec) (struct inode *);
|
||||
int (*setlease)(struct file *, long, struct file_lock **);
|
||||
+ int (*fsetattr)(struct file *, struct iattr *);
|
||||
};
|
||||
|
||||
struct inode_operations {
|
||||
@@ -1799,6 +1793,7 @@ extern int do_remount_sb(struct super_bl
|
||||
extern sector_t bmap(struct inode *, sector_t);
|
||||
#endif
|
||||
extern int notify_change(struct dentry *, struct vfsmount *, struct iattr *);
|
||||
+extern int fnotify_change(struct dentry *, struct vfsmount *, struct iattr *, struct file *);
|
||||
extern int inode_permission(struct inode *, int);
|
||||
extern int generic_permission(struct inode *, int,
|
||||
int (*check_acl)(struct inode *, int));
|
||||
@@ -1,41 +0,0 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: Pass struct path down to remove_suid and children
|
||||
|
||||
Required by a later patch that adds a struct vfsmount parameter to
|
||||
notify_change().
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
|
||||
mm/filemap.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/mm/filemap.c
|
||||
+++ b/mm/filemap.c
|
||||
@@ -1826,12 +1826,12 @@ int should_remove_suid(struct dentry *de
|
||||
}
|
||||
EXPORT_SYMBOL(should_remove_suid);
|
||||
|
||||
-static int __remove_suid(struct dentry *dentry, int kill)
|
||||
+static int __remove_suid(struct path *path, int kill)
|
||||
{
|
||||
struct iattr newattrs;
|
||||
|
||||
newattrs.ia_valid = ATTR_FORCE | kill;
|
||||
- return notify_change(dentry, &newattrs);
|
||||
+ return notify_change(path->dentry, &newattrs);
|
||||
}
|
||||
|
||||
int file_remove_suid(struct file *file)
|
||||
@@ -1846,7 +1846,7 @@ int file_remove_suid(struct file *file)
|
||||
if (killpriv)
|
||||
error = security_inode_killpriv(dentry);
|
||||
if (!error && killsuid)
|
||||
- error = __remove_suid(dentry, killsuid);
|
||||
+ error = __remove_suid(&file->f_path, killsuid);
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_create LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/namei.c | 2 +-
|
||||
include/linux/security.h | 9 ++++++---
|
||||
security/capability.c | 2 +-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 3 ++-
|
||||
5 files changed, 13 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -1543,7 +1543,7 @@ int vfs_create(struct inode *dir, struct
|
||||
return -EACCES; /* shouldn't it be ENOSYS? */
|
||||
mode &= S_IALLUGO;
|
||||
mode |= S_IFREG;
|
||||
- error = security_inode_create(dir, dentry, mode);
|
||||
+ error = security_inode_create(dir, dentry, nd ? nd->path.mnt : NULL, mode);
|
||||
if (error)
|
||||
return error;
|
||||
DQUOT_INIT(dir);
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -337,6 +337,7 @@ static inline void security_free_mnt_opt
|
||||
* Check permission to create a regular file.
|
||||
* @dir contains inode structure of the parent of the new file.
|
||||
* @dentry contains the dentry structure for the file to be created.
|
||||
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
|
||||
* @mode contains the file mode of the file to be created.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_link:
|
||||
@@ -1354,8 +1355,8 @@ struct security_operations {
|
||||
void (*inode_free_security) (struct inode *inode);
|
||||
int (*inode_init_security) (struct inode *inode, struct inode *dir,
|
||||
char **name, void **value, size_t *len);
|
||||
- int (*inode_create) (struct inode *dir,
|
||||
- struct dentry *dentry, int mode);
|
||||
+ int (*inode_create) (struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mode);
|
||||
int (*inode_link) (struct dentry *old_dentry,
|
||||
struct inode *dir, struct dentry *new_dentry);
|
||||
int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
|
||||
@@ -1622,7 +1623,8 @@ int security_inode_alloc(struct inode *i
|
||||
void security_inode_free(struct inode *inode);
|
||||
int security_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
char **name, void **value, size_t *len);
|
||||
-int security_inode_create(struct inode *dir, struct dentry *dentry, int mode);
|
||||
+int security_inode_create(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mode);
|
||||
int security_inode_link(struct dentry *old_dentry, struct inode *dir,
|
||||
struct dentry *new_dentry);
|
||||
int security_inode_unlink(struct inode *dir, struct dentry *dentry);
|
||||
@@ -1968,6 +1970,7 @@ static inline int security_inode_init_se
|
||||
|
||||
static inline int security_inode_create(struct inode *dir,
|
||||
struct dentry *dentry,
|
||||
+ struct vfsmount *mnt,
|
||||
int mode)
|
||||
{
|
||||
return 0;
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -155,7 +155,7 @@ static int cap_inode_init_security(struc
|
||||
}
|
||||
|
||||
static int cap_inode_create(struct inode *inode, struct dentry *dentry,
|
||||
- int mask)
|
||||
+ struct vfsmount *mnt, int mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -355,11 +355,12 @@ int security_inode_init_security(struct
|
||||
}
|
||||
EXPORT_SYMBOL(security_inode_init_security);
|
||||
|
||||
-int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)
|
||||
+int security_inode_create(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mode)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dir)))
|
||||
return 0;
|
||||
- return security_ops->inode_create(dir, dentry, mode);
|
||||
+ return security_ops->inode_create(dir, dentry, mnt, mode);
|
||||
}
|
||||
|
||||
int security_inode_link(struct dentry *old_dentry, struct inode *dir,
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2566,7 +2566,8 @@ static int selinux_inode_init_security(s
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
|
||||
+static int selinux_inode_create(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mask)
|
||||
{
|
||||
return may_create(dir, dentry, SECCLASS_FILE);
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_getxattr LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/xattr.c | 2 +-
|
||||
include/linux/security.h | 11 +++++++----
|
||||
security/capability.c | 3 ++-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 3 ++-
|
||||
security/smack/smack_lsm.c | 4 +++-
|
||||
6 files changed, 18 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -141,7 +141,7 @@ vfs_getxattr(struct dentry *dentry, stru
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
- error = security_inode_getxattr(dentry, name);
|
||||
+ error = security_inode_getxattr(dentry, mnt, name);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -446,7 +446,7 @@ static inline void security_free_mnt_opt
|
||||
* @value identified by @name for @dentry and @mnt.
|
||||
* @inode_getxattr:
|
||||
* Check permission before obtaining the extended attributes
|
||||
- * identified by @name for @dentry.
|
||||
+ * identified by @name for @dentry and @mnt.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_listxattr:
|
||||
* Check permission before obtaining the list of extended attribute
|
||||
@@ -1400,7 +1400,8 @@ struct security_operations {
|
||||
struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
- int (*inode_getxattr) (struct dentry *dentry, const char *name);
|
||||
+ int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name);
|
||||
int (*inode_listxattr) (struct dentry *dentry);
|
||||
int (*inode_removexattr) (struct dentry *dentry, const char *name);
|
||||
int (*inode_need_killpriv) (struct dentry *dentry);
|
||||
@@ -1676,7 +1677,8 @@ int security_inode_setxattr(struct dentr
|
||||
void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
-int security_inode_getxattr(struct dentry *dentry, const char *name);
|
||||
+int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name);
|
||||
int security_inode_listxattr(struct dentry *dentry);
|
||||
int security_inode_removexattr(struct dentry *dentry, const char *name);
|
||||
int security_inode_need_killpriv(struct dentry *dentry);
|
||||
@@ -2113,7 +2115,8 @@ static inline void security_inode_post_s
|
||||
{ }
|
||||
|
||||
static inline int security_inode_getxattr(struct dentry *dentry,
|
||||
- const char *name)
|
||||
+ struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -241,7 +241,8 @@ static void cap_inode_post_setxattr(stru
|
||||
{
|
||||
}
|
||||
|
||||
-static int cap_inode_getxattr(struct dentry *dentry, const char *name)
|
||||
+static int cap_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -488,11 +488,12 @@ void security_inode_post_setxattr(struct
|
||||
flags);
|
||||
}
|
||||
|
||||
-int security_inode_getxattr(struct dentry *dentry, const char *name)
|
||||
+int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return 0;
|
||||
- return security_ops->inode_getxattr(dentry, name);
|
||||
+ return security_ops->inode_getxattr(dentry, mnt, name);
|
||||
}
|
||||
|
||||
int security_inode_listxattr(struct dentry *dentry)
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2796,7 +2796,8 @@ static void selinux_inode_post_setxattr(
|
||||
return;
|
||||
}
|
||||
|
||||
-static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
|
||||
+static int selinux_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
|
||||
}
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -673,11 +673,13 @@ static void smack_inode_post_setxattr(st
|
||||
/*
|
||||
* smack_inode_getxattr - Smack check on getxattr
|
||||
* @dentry: the object
|
||||
+ * @mnt: unused
|
||||
* @name: unused
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
-static int smack_inode_getxattr(struct dentry *dentry, const char *name)
|
||||
+static int smack_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass the struct vfsmounts to the inode_link LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/namei.c | 3 ++-
|
||||
include/linux/security.h | 18 ++++++++++++------
|
||||
security/capability.c | 5 +++--
|
||||
security/security.c | 8 +++++---
|
||||
security/selinux/hooks.c | 9 +++++++--
|
||||
security/smack/smack_lsm.c | 5 +++--
|
||||
6 files changed, 32 insertions(+), 16 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2437,7 +2437,8 @@ int vfs_link(struct dentry *old_dentry,
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
return -EPERM;
|
||||
|
||||
- error = security_inode_link(old_dentry, dir, new_dentry);
|
||||
+ error = security_inode_link(old_dentry, old_mnt, dir, new_dentry,
|
||||
+ new_mnt);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -343,8 +343,10 @@ static inline void security_free_mnt_opt
|
||||
* @inode_link:
|
||||
* Check permission before creating a new hard link to a file.
|
||||
* @old_dentry contains the dentry structure for an existing link to the file.
|
||||
+ * @old_mnt is the vfsmount corresponding to @old_dentry (may be NULL).
|
||||
* @dir contains the inode structure of the parent directory of the new link.
|
||||
* @new_dentry contains the dentry structure for the new link.
|
||||
+ * @new_mnt is the vfsmount corresponding to @new_dentry (may be NULL).
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_unlink:
|
||||
* Check the permission to remove a hard link to a file.
|
||||
@@ -1362,8 +1364,9 @@ struct security_operations {
|
||||
char **name, void **value, size_t *len);
|
||||
int (*inode_create) (struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, int mode);
|
||||
- int (*inode_link) (struct dentry *old_dentry,
|
||||
- struct inode *dir, struct dentry *new_dentry);
|
||||
+ int (*inode_link) (struct dentry *old_dentry, struct vfsmount *old_mnt,
|
||||
+ struct inode *dir, struct dentry *new_dentry,
|
||||
+ struct vfsmount *new_mnt);
|
||||
int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
|
||||
int (*inode_symlink) (struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, const char *old_name);
|
||||
@@ -1632,8 +1635,9 @@ int security_inode_init_security(struct
|
||||
char **name, void **value, size_t *len);
|
||||
int security_inode_create(struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, int mode);
|
||||
-int security_inode_link(struct dentry *old_dentry, struct inode *dir,
|
||||
- struct dentry *new_dentry);
|
||||
+int security_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt,
|
||||
+ struct inode *dir, struct dentry *new_dentry,
|
||||
+ struct vfsmount *new_mnt);
|
||||
int security_inode_unlink(struct inode *dir, struct dentry *dentry);
|
||||
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, const char *old_name);
|
||||
@@ -1987,8 +1991,10 @@ static inline int security_inode_create(
|
||||
}
|
||||
|
||||
static inline int security_inode_link(struct dentry *old_dentry,
|
||||
- struct inode *dir,
|
||||
- struct dentry *new_dentry)
|
||||
+ struct vfsmount *old_mnt,
|
||||
+ struct inode *dir,
|
||||
+ struct dentry *new_dentry,
|
||||
+ struct vfsmount *new_mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -160,8 +160,9 @@ static int cap_inode_create(struct inode
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_link(struct dentry *old_dentry, struct inode *inode,
|
||||
- struct dentry *new_dentry)
|
||||
+static int cap_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt,
|
||||
+ struct inode *inode,
|
||||
+ struct dentry *new_dentry, struct vfsmount *new_mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -363,12 +363,14 @@ int security_inode_create(struct inode *
|
||||
return security_ops->inode_create(dir, dentry, mnt, mode);
|
||||
}
|
||||
|
||||
-int security_inode_link(struct dentry *old_dentry, struct inode *dir,
|
||||
- struct dentry *new_dentry)
|
||||
+int security_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt,
|
||||
+ struct inode *dir, struct dentry *new_dentry,
|
||||
+ struct vfsmount *new_mnt)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(old_dentry->d_inode)))
|
||||
return 0;
|
||||
- return security_ops->inode_link(old_dentry, dir, new_dentry);
|
||||
+ return security_ops->inode_link(old_dentry, old_mnt, dir,
|
||||
+ new_dentry, new_mnt);
|
||||
}
|
||||
|
||||
int security_inode_unlink(struct inode *dir, struct dentry *dentry)
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2572,11 +2572,16 @@ static int selinux_inode_create(struct i
|
||||
return may_create(dir, dentry, SECCLASS_FILE);
|
||||
}
|
||||
|
||||
-static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
|
||||
+static int selinux_inode_link(struct dentry *old_dentry,
|
||||
+ struct vfsmount *old_mnt,
|
||||
+ struct inode *dir,
|
||||
+ struct dentry *new_dentry,
|
||||
+ struct vfsmount *new_mnt)
|
||||
{
|
||||
int rc;
|
||||
|
||||
- rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
|
||||
+ rc = secondary_ops->inode_link(old_dentry, old_mnt, dir, new_dentry,
|
||||
+ new_mnt);
|
||||
if (rc)
|
||||
return rc;
|
||||
return may_link(dir, old_dentry, MAY_LINK);
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -432,8 +432,9 @@ static int smack_inode_init_security(str
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
-static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
|
||||
- struct dentry *new_dentry)
|
||||
+static int smack_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt,
|
||||
+ struct inode *dir,
|
||||
+ struct dentry *new_dentry, struct vfsmount *new_mnt)
|
||||
{
|
||||
int rc;
|
||||
char *isp;
|
||||
@@ -1,105 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_listxattr LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/xattr.c | 2 +-
|
||||
include/linux/security.h | 9 +++++----
|
||||
security/capability.c | 2 +-
|
||||
security/security.c | 4 ++--
|
||||
security/selinux/hooks.c | 2 +-
|
||||
5 files changed, 10 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -174,7 +174,7 @@ vfs_listxattr(struct dentry *dentry, str
|
||||
struct inode *inode = dentry->d_inode;
|
||||
ssize_t error;
|
||||
|
||||
- error = security_inode_listxattr(dentry);
|
||||
+ error = security_inode_listxattr(dentry, mnt);
|
||||
if (error)
|
||||
return error;
|
||||
error = -EOPNOTSUPP;
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -450,7 +450,7 @@ static inline void security_free_mnt_opt
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_listxattr:
|
||||
* Check permission before obtaining the list of extended attribute
|
||||
- * names for @dentry.
|
||||
+ * names for @dentry and @mnt.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_removexattr:
|
||||
* Check permission before removing the extended attribute
|
||||
@@ -1402,7 +1402,7 @@ struct security_operations {
|
||||
size_t size, int flags);
|
||||
int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name);
|
||||
- int (*inode_listxattr) (struct dentry *dentry);
|
||||
+ int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt);
|
||||
int (*inode_removexattr) (struct dentry *dentry, const char *name);
|
||||
int (*inode_need_killpriv) (struct dentry *dentry);
|
||||
int (*inode_killpriv) (struct dentry *dentry);
|
||||
@@ -1679,7 +1679,7 @@ void security_inode_post_setxattr(struct
|
||||
size_t size, int flags);
|
||||
int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name);
|
||||
-int security_inode_listxattr(struct dentry *dentry);
|
||||
+int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt);
|
||||
int security_inode_removexattr(struct dentry *dentry, const char *name);
|
||||
int security_inode_need_killpriv(struct dentry *dentry);
|
||||
int security_inode_killpriv(struct dentry *dentry);
|
||||
@@ -2121,7 +2121,8 @@ static inline int security_inode_getxatt
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static inline int security_inode_listxattr(struct dentry *dentry)
|
||||
+static inline int security_inode_listxattr(struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -247,7 +247,7 @@ static int cap_inode_getxattr(struct den
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_listxattr(struct dentry *dentry)
|
||||
+static int cap_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -496,11 +496,11 @@ int security_inode_getxattr(struct dentr
|
||||
return security_ops->inode_getxattr(dentry, mnt, name);
|
||||
}
|
||||
|
||||
-int security_inode_listxattr(struct dentry *dentry)
|
||||
+int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return 0;
|
||||
- return security_ops->inode_listxattr(dentry);
|
||||
+ return security_ops->inode_listxattr(dentry, mnt);
|
||||
}
|
||||
|
||||
int security_inode_removexattr(struct dentry *dentry, const char *name)
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2802,7 +2802,7 @@ static int selinux_inode_getxattr(struct
|
||||
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
|
||||
}
|
||||
|
||||
-static int selinux_inode_listxattr(struct dentry *dentry)
|
||||
+static int selinux_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
|
||||
{
|
||||
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_mkdir LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/namei.c | 2 +-
|
||||
include/linux/security.h | 8 ++++++--
|
||||
security/capability.c | 2 +-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 3 ++-
|
||||
5 files changed, 13 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2089,7 +2089,7 @@ int vfs_mkdir(struct inode *dir, struct
|
||||
return -EPERM;
|
||||
|
||||
mode &= (S_IRWXUGO|S_ISVTX);
|
||||
- error = security_inode_mkdir(dir, dentry, mode);
|
||||
+ error = security_inode_mkdir(dir, dentry, mnt, mode);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -362,6 +362,7 @@ static inline void security_free_mnt_opt
|
||||
* associated with inode strcture @dir.
|
||||
* @dir containst the inode structure of parent of the directory to be created.
|
||||
* @dentry contains the dentry structure of new directory.
|
||||
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
|
||||
* @mode contains the mode of new directory.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_rmdir:
|
||||
@@ -1363,7 +1364,8 @@ struct security_operations {
|
||||
int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
|
||||
int (*inode_symlink) (struct inode *dir,
|
||||
struct dentry *dentry, const char *old_name);
|
||||
- int (*inode_mkdir) (struct inode *dir, struct dentry *dentry, int mode);
|
||||
+ int (*inode_mkdir) (struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mode);
|
||||
int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
|
||||
int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
|
||||
int mode, dev_t dev);
|
||||
@@ -1632,7 +1634,8 @@ int security_inode_link(struct dentry *o
|
||||
int security_inode_unlink(struct inode *dir, struct dentry *dentry);
|
||||
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
|
||||
const char *old_name);
|
||||
-int security_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode);
|
||||
+int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mode);
|
||||
int security_inode_rmdir(struct inode *dir, struct dentry *dentry);
|
||||
int security_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev);
|
||||
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
@@ -2001,6 +2004,7 @@ static inline int security_inode_symlink
|
||||
|
||||
static inline int security_inode_mkdir(struct inode *dir,
|
||||
struct dentry *dentry,
|
||||
+ struct vfsmount *mnt,
|
||||
int mode)
|
||||
{
|
||||
return 0;
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -178,7 +178,7 @@ static int cap_inode_symlink(struct inod
|
||||
}
|
||||
|
||||
static int cap_inode_mkdir(struct inode *inode, struct dentry *dentry,
|
||||
- int mask)
|
||||
+ struct vfsmount *mnt, int mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -386,11 +386,12 @@ int security_inode_symlink(struct inode
|
||||
return security_ops->inode_symlink(dir, dentry, old_name);
|
||||
}
|
||||
|
||||
-int security_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
+int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mode)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dir)))
|
||||
return 0;
|
||||
- return security_ops->inode_mkdir(dir, dentry, mode);
|
||||
+ return security_ops->inode_mkdir(dir, dentry, mnt, mode);
|
||||
}
|
||||
|
||||
int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2597,7 +2597,8 @@ static int selinux_inode_symlink(struct
|
||||
return may_create(dir, dentry, SECCLASS_LNK_FILE);
|
||||
}
|
||||
|
||||
-static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
|
||||
+static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mask)
|
||||
{
|
||||
return may_create(dir, dentry, SECCLASS_DIR);
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_mknod LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/namei.c | 6 +++---
|
||||
include/linux/security.h | 7 +++++--
|
||||
security/capability.c | 2 +-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 5 +++--
|
||||
5 files changed, 15 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -1994,7 +1994,7 @@ int vfs_mknod(struct inode *dir, struct
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
- error = security_inode_mknod(dir, dentry, mode, dev);
|
||||
+ error = security_inode_mknod(dir, dentry, mnt, mode, dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@@ -2056,11 +2056,11 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const
|
||||
break;
|
||||
case S_IFCHR: case S_IFBLK:
|
||||
error = vfs_mknod(nd.path.dentry->d_inode, dentry,
|
||||
- nd.path, mode, new_decode_dev(dev));
|
||||
+ nd.path.mnt, mode, new_decode_dev(dev));
|
||||
break;
|
||||
case S_IFIFO: case S_IFSOCK:
|
||||
error = vfs_mknod(nd.path.dentry->d_inode, dentry,
|
||||
- nd.path, mode, 0);
|
||||
+ nd.path.mnt, mode, 0);
|
||||
break;
|
||||
}
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -377,6 +377,7 @@ static inline void security_free_mnt_opt
|
||||
* and not this hook.
|
||||
* @dir contains the inode structure of parent of the new file.
|
||||
* @dentry contains the dentry structure of the new file.
|
||||
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
|
||||
* @mode contains the mode of the new file.
|
||||
* @dev contains the device number.
|
||||
* Return 0 if permission is granted.
|
||||
@@ -1368,7 +1369,7 @@ struct security_operations {
|
||||
struct vfsmount *mnt, int mode);
|
||||
int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
|
||||
int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
|
||||
- int mode, dev_t dev);
|
||||
+ struct vfsmount *mnt, int mode, dev_t dev);
|
||||
int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry);
|
||||
int (*inode_readlink) (struct dentry *dentry);
|
||||
@@ -1637,7 +1638,8 @@ int security_inode_symlink(struct inode
|
||||
int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, int mode);
|
||||
int security_inode_rmdir(struct inode *dir, struct dentry *dentry);
|
||||
-int security_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev);
|
||||
+int security_inode_mknod(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mode, dev_t dev);
|
||||
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry);
|
||||
int security_inode_readlink(struct dentry *dentry);
|
||||
@@ -2018,6 +2020,7 @@ static inline int security_inode_rmdir(s
|
||||
|
||||
static inline int security_inode_mknod(struct inode *dir,
|
||||
struct dentry *dentry,
|
||||
+ struct vfsmount *mnt,
|
||||
int mode, dev_t dev)
|
||||
{
|
||||
return 0;
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -189,7 +189,7 @@ static int cap_inode_rmdir(struct inode
|
||||
}
|
||||
|
||||
static int cap_inode_mknod(struct inode *inode, struct dentry *dentry,
|
||||
- int mode, dev_t dev)
|
||||
+ struct vfsmount *mnt, int mode, dev_t dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -401,11 +401,12 @@ int security_inode_rmdir(struct inode *d
|
||||
return security_ops->inode_rmdir(dir, dentry);
|
||||
}
|
||||
|
||||
-int security_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
|
||||
+int security_inode_mknod(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mode, dev_t dev)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dir)))
|
||||
return 0;
|
||||
- return security_ops->inode_mknod(dir, dentry, mode, dev);
|
||||
+ return security_ops->inode_mknod(dir, dentry, mnt, mode, dev);
|
||||
}
|
||||
|
||||
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2608,11 +2608,12 @@ static int selinux_inode_rmdir(struct in
|
||||
return may_link(dir, dentry, MAY_RMDIR);
|
||||
}
|
||||
|
||||
-static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
|
||||
+static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, int mode, dev_t dev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
- rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
|
||||
+ rc = secondary_ops->inode_mknod(dir, dentry, mnt, mode, dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_readlink LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/stat.c | 2 +-
|
||||
include/linux/security.h | 8 +++++---
|
||||
security/capability.c | 2 +-
|
||||
security/security.c | 4 ++--
|
||||
security/selinux/hooks.c | 2 +-
|
||||
5 files changed, 10 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/stat.c
|
||||
+++ b/fs/stat.c
|
||||
@@ -308,7 +308,7 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, co
|
||||
|
||||
error = -EINVAL;
|
||||
if (inode->i_op && inode->i_op->readlink) {
|
||||
- error = security_inode_readlink(path.dentry);
|
||||
+ error = security_inode_readlink(path.dentry, path.mnt);
|
||||
if (!error) {
|
||||
touch_atime(path.mnt, path.dentry);
|
||||
error = inode->i_op->readlink(path.dentry,
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -392,6 +392,7 @@ static inline void security_free_mnt_opt
|
||||
* @inode_readlink:
|
||||
* Check the permission to read the symbolic link.
|
||||
* @dentry contains the dentry structure for the file link.
|
||||
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_follow_link:
|
||||
* Check permission to follow a symbolic link when looking up a pathname.
|
||||
@@ -1373,7 +1374,7 @@ struct security_operations {
|
||||
struct vfsmount *mnt, int mode, dev_t dev);
|
||||
int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry);
|
||||
- int (*inode_readlink) (struct dentry *dentry);
|
||||
+ int (*inode_readlink) (struct dentry *dentry, struct vfsmount *mnt);
|
||||
int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
|
||||
int (*inode_permission) (struct inode *inode, int mask);
|
||||
int (*inode_setattr) (struct dentry *dentry, struct vfsmount *,
|
||||
@@ -1643,7 +1644,7 @@ int security_inode_mknod(struct inode *d
|
||||
struct vfsmount *mnt, int mode, dev_t dev);
|
||||
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry);
|
||||
-int security_inode_readlink(struct dentry *dentry);
|
||||
+int security_inode_readlink(struct dentry *dentry, struct vfsmount *mnt);
|
||||
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
|
||||
int security_inode_permission(struct inode *inode, int mask);
|
||||
int security_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
@@ -2036,7 +2037,8 @@ static inline int security_inode_rename(
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static inline int security_inode_readlink(struct dentry *dentry)
|
||||
+static inline int security_inode_readlink(struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -200,7 +200,7 @@ static int cap_inode_rename(struct inode
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_readlink(struct dentry *dentry)
|
||||
+static int cap_inode_readlink(struct dentry *dentry, struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -419,11 +419,11 @@ int security_inode_rename(struct inode *
|
||||
new_dir, new_dentry);
|
||||
}
|
||||
|
||||
-int security_inode_readlink(struct dentry *dentry)
|
||||
+int security_inode_readlink(struct dentry *dentry, struct vfsmount *mnt)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return 0;
|
||||
- return security_ops->inode_readlink(dentry);
|
||||
+ return security_ops->inode_readlink(dentry, mnt);
|
||||
}
|
||||
|
||||
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2627,7 +2627,7 @@ static int selinux_inode_rename(struct i
|
||||
return may_rename(old_inode, old_dentry, new_inode, new_dentry);
|
||||
}
|
||||
|
||||
-static int selinux_inode_readlink(struct dentry *dentry)
|
||||
+static int selinux_inode_readlink(struct dentry *dentry, struct vfsmount *mnt)
|
||||
{
|
||||
return dentry_has_perm(current, NULL, dentry, FILE__READ);
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_removexattr LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/xattr.c | 2 +-
|
||||
include/linux/security.h | 14 +++++++++-----
|
||||
security/commoncap.c | 3 ++-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 3 ++-
|
||||
security/smack/smack_lsm.c | 6 ++++--
|
||||
6 files changed, 21 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -202,7 +202,7 @@ vfs_removexattr(struct dentry *dentry, s
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
- error = security_inode_removexattr(dentry, name);
|
||||
+ error = security_inode_removexattr(dentry, mnt, name);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -57,7 +57,8 @@ extern int cap_bprm_secureexec(struct li
|
||||
extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value, size_t size,
|
||||
int flags);
|
||||
-extern int cap_inode_removexattr(struct dentry *dentry, const char *name);
|
||||
+extern int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name);
|
||||
extern int cap_inode_need_killpriv(struct dentry *dentry);
|
||||
extern int cap_inode_killpriv(struct dentry *dentry);
|
||||
extern int cap_task_post_setuid(uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
|
||||
@@ -1403,7 +1404,8 @@ struct security_operations {
|
||||
int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name);
|
||||
int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt);
|
||||
- int (*inode_removexattr) (struct dentry *dentry, const char *name);
|
||||
+ int (*inode_removexattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name);
|
||||
int (*inode_need_killpriv) (struct dentry *dentry);
|
||||
int (*inode_killpriv) (struct dentry *dentry);
|
||||
int (*inode_getsecurity) (const struct inode *inode, const char *name, void **buffer, bool alloc);
|
||||
@@ -1680,7 +1682,8 @@ void security_inode_post_setxattr(struct
|
||||
int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name);
|
||||
int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt);
|
||||
-int security_inode_removexattr(struct dentry *dentry, const char *name);
|
||||
+int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name);
|
||||
int security_inode_need_killpriv(struct dentry *dentry);
|
||||
int security_inode_killpriv(struct dentry *dentry);
|
||||
int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc);
|
||||
@@ -2128,9 +2131,10 @@ static inline int security_inode_listxat
|
||||
}
|
||||
|
||||
static inline int security_inode_removexattr(struct dentry *dentry,
|
||||
- const char *name)
|
||||
+ struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
- return cap_inode_removexattr(dentry, name);
|
||||
+ return cap_inode_removexattr(dentry, mnt, name);
|
||||
}
|
||||
|
||||
static inline int security_inode_need_killpriv(struct dentry *dentry)
|
||||
--- a/security/commoncap.c
|
||||
+++ b/security/commoncap.c
|
||||
@@ -429,7 +429,8 @@ int cap_inode_setxattr(struct dentry *de
|
||||
return 0;
|
||||
}
|
||||
|
||||
-int cap_inode_removexattr(struct dentry *dentry, const char *name)
|
||||
+int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
if (!strcmp(name, XATTR_NAME_CAPS)) {
|
||||
if (!capable(CAP_SETFCAP))
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -503,11 +503,12 @@ int security_inode_listxattr(struct dent
|
||||
return security_ops->inode_listxattr(dentry, mnt);
|
||||
}
|
||||
|
||||
-int security_inode_removexattr(struct dentry *dentry, const char *name)
|
||||
+int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return 0;
|
||||
- return security_ops->inode_removexattr(dentry, name);
|
||||
+ return security_ops->inode_removexattr(dentry, mnt, name);
|
||||
}
|
||||
|
||||
int security_inode_need_killpriv(struct dentry *dentry)
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2807,7 +2807,8 @@ static int selinux_inode_listxattr(struc
|
||||
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
|
||||
}
|
||||
|
||||
-static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
|
||||
+static int selinux_inode_removexattr(struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, const char *name)
|
||||
{
|
||||
if (strcmp(name, XATTR_NAME_SELINUX))
|
||||
return selinux_inode_setotherxattr(dentry, name);
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -687,13 +687,15 @@ static int smack_inode_getxattr(struct d
|
||||
/*
|
||||
* smack_inode_removexattr - Smack check on removexattr
|
||||
* @dentry: the object
|
||||
+ * @mnt: unused
|
||||
* @name: name of the attribute
|
||||
*
|
||||
* Removing the Smack attribute requires CAP_MAC_ADMIN
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
-static int smack_inode_removexattr(struct dentry *dentry, const char *name)
|
||||
+static int smack_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@@ -703,7 +705,7 @@ static int smack_inode_removexattr(struc
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
rc = -EPERM;
|
||||
} else
|
||||
- rc = cap_inode_removexattr(dentry, name);
|
||||
+ rc = cap_inode_removexattr(dentry, mnt, name);
|
||||
|
||||
if (rc == 0)
|
||||
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
|
||||
@@ -1,160 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_rename LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/namei.c | 6 ++++--
|
||||
include/linux/security.h | 13 ++++++++++---
|
||||
security/capability.c | 3 ++-
|
||||
security/security.c | 7 ++++---
|
||||
security/selinux/hooks.c | 8 ++++++--
|
||||
security/smack/smack_lsm.c | 6 +++++-
|
||||
6 files changed, 31 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2563,7 +2563,8 @@ static int vfs_rename_dir(struct inode *
|
||||
return error;
|
||||
}
|
||||
|
||||
- error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
|
||||
+ error = security_inode_rename(old_dir, old_dentry, old_mnt,
|
||||
+ new_dir, new_dentry, new_mnt);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@@ -2597,7 +2598,8 @@ static int vfs_rename_other(struct inode
|
||||
struct inode *target;
|
||||
int error;
|
||||
|
||||
- error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
|
||||
+ error = security_inode_rename(old_dir, old_dentry, old_mnt,
|
||||
+ new_dir, new_dentry, new_mnt);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -390,8 +390,10 @@ static inline void security_free_mnt_opt
|
||||
* Check for permission to rename a file or directory.
|
||||
* @old_dir contains the inode structure for parent of the old link.
|
||||
* @old_dentry contains the dentry structure of the old link.
|
||||
+ * @old_mnt is the vfsmount corresponding to @old_dentry (may be NULL).
|
||||
* @new_dir contains the inode structure for parent of the new link.
|
||||
* @new_dentry contains the dentry structure of the new link.
|
||||
+ * @new_mnt is the vfsmount corresponding to @new_dentry (may be NULL).
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_readlink:
|
||||
* Check the permission to read the symbolic link.
|
||||
@@ -1380,7 +1382,9 @@ struct security_operations {
|
||||
int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, int mode, dev_t dev);
|
||||
int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
|
||||
- struct inode *new_dir, struct dentry *new_dentry);
|
||||
+ struct vfsmount *old_mnt,
|
||||
+ struct inode *new_dir, struct dentry *new_dentry,
|
||||
+ struct vfsmount *new_mnt);
|
||||
int (*inode_readlink) (struct dentry *dentry, struct vfsmount *mnt);
|
||||
int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
|
||||
int (*inode_permission) (struct inode *inode, int mask);
|
||||
@@ -1653,7 +1657,8 @@ int security_inode_rmdir(struct inode *d
|
||||
int security_inode_mknod(struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, int mode, dev_t dev);
|
||||
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
- struct inode *new_dir, struct dentry *new_dentry);
|
||||
+ struct vfsmount *old_mnt, struct inode *new_dir,
|
||||
+ struct dentry *new_dentry, struct vfsmount *new_mnt);
|
||||
int security_inode_readlink(struct dentry *dentry, struct vfsmount *mnt);
|
||||
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
|
||||
int security_inode_permission(struct inode *inode, int mask);
|
||||
@@ -2045,8 +2050,10 @@ static inline int security_inode_mknod(s
|
||||
|
||||
static inline int security_inode_rename(struct inode *old_dir,
|
||||
struct dentry *old_dentry,
|
||||
+ struct vfsmount *old_mnt,
|
||||
struct inode *new_dir,
|
||||
- struct dentry *new_dentry)
|
||||
+ struct dentry *new_dentry,
|
||||
+ struct vfsmount *new_mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -198,7 +198,8 @@ static int cap_inode_mknod(struct inode
|
||||
}
|
||||
|
||||
static int cap_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
|
||||
- struct inode *new_inode, struct dentry *new_dentry)
|
||||
+ struct vfsmount *old_mnt, struct inode *new_inode,
|
||||
+ struct dentry *new_dentry, struct vfsmount *new_mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -414,13 +414,14 @@ int security_inode_mknod(struct inode *d
|
||||
}
|
||||
|
||||
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
- struct inode *new_dir, struct dentry *new_dentry)
|
||||
+ struct vfsmount *old_mnt, struct inode *new_dir,
|
||||
+ struct dentry *new_dentry, struct vfsmount *new_mnt)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(old_dentry->d_inode) ||
|
||||
(new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode))))
|
||||
return 0;
|
||||
- return security_ops->inode_rename(old_dir, old_dentry,
|
||||
- new_dir, new_dentry);
|
||||
+ return security_ops->inode_rename(old_dir, old_dentry, old_mnt,
|
||||
+ new_dir, new_dentry, new_mnt);
|
||||
}
|
||||
|
||||
int security_inode_readlink(struct dentry *dentry, struct vfsmount *mnt)
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2628,8 +2628,12 @@ static int selinux_inode_mknod(struct in
|
||||
return may_create(dir, dentry, inode_mode_to_security_class(mode));
|
||||
}
|
||||
|
||||
-static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
|
||||
- struct inode *new_inode, struct dentry *new_dentry)
|
||||
+static int selinux_inode_rename(struct inode *old_inode,
|
||||
+ struct dentry *old_dentry,
|
||||
+ struct vfsmount *old_mnt,
|
||||
+ struct inode *new_inode,
|
||||
+ struct dentry *new_dentry,
|
||||
+ struct vfsmount *new_mnt)
|
||||
{
|
||||
return may_rename(old_inode, old_dentry, new_inode, new_dentry);
|
||||
}
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -509,8 +509,10 @@ static int smack_inode_rmdir(struct inod
|
||||
* smack_inode_rename - Smack check on rename
|
||||
* @old_inode: the old directory
|
||||
* @old_dentry: unused
|
||||
+ * @old_mnt: unused
|
||||
* @new_inode: the new directory
|
||||
* @new_dentry: unused
|
||||
+ * @new_mnt: unused
|
||||
*
|
||||
* Read and write access is required on both the old and
|
||||
* new directories.
|
||||
@@ -519,8 +521,10 @@ static int smack_inode_rmdir(struct inod
|
||||
*/
|
||||
static int smack_inode_rename(struct inode *old_inode,
|
||||
struct dentry *old_dentry,
|
||||
+ struct vfsmount *old_mnt,
|
||||
struct inode *new_inode,
|
||||
- struct dentry *new_dentry)
|
||||
+ struct dentry *new_dentry,
|
||||
+ struct vfsmount *new_mnt)
|
||||
{
|
||||
int rc;
|
||||
char *isp;
|
||||
@@ -1,127 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_rmdir LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/namei.c | 2 +-
|
||||
include/linux/security.h | 10 +++++++---
|
||||
security/capability.c | 3 ++-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 3 ++-
|
||||
security/smack/smack_lsm.c | 4 +++-
|
||||
6 files changed, 18 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2184,7 +2184,7 @@ int vfs_rmdir(struct inode *dir, struct
|
||||
if (d_mountpoint(dentry))
|
||||
error = -EBUSY;
|
||||
else {
|
||||
- error = security_inode_rmdir(dir, dentry);
|
||||
+ error = security_inode_rmdir(dir, dentry, mnt);
|
||||
if (!error) {
|
||||
error = dir->i_op->rmdir(dir, dentry);
|
||||
if (!error)
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -372,6 +372,7 @@ static inline void security_free_mnt_opt
|
||||
* Check the permission to remove a directory.
|
||||
* @dir contains the inode structure of parent of the directory to be removed.
|
||||
* @dentry contains the dentry structure of directory to be removed.
|
||||
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_mknod:
|
||||
* Check permissions when creating a special file (or a socket or a fifo
|
||||
@@ -1372,7 +1373,8 @@ struct security_operations {
|
||||
struct vfsmount *mnt, const char *old_name);
|
||||
int (*inode_mkdir) (struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, int mode);
|
||||
- int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
|
||||
+ int (*inode_rmdir) (struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt);
|
||||
int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, int mode, dev_t dev);
|
||||
int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
|
||||
@@ -1643,7 +1645,8 @@ int security_inode_symlink(struct inode
|
||||
struct vfsmount *mnt, const char *old_name);
|
||||
int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, int mode);
|
||||
-int security_inode_rmdir(struct inode *dir, struct dentry *dentry);
|
||||
+int security_inode_rmdir(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt);
|
||||
int security_inode_mknod(struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, int mode, dev_t dev);
|
||||
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
@@ -2022,7 +2025,8 @@ static inline int security_inode_mkdir(s
|
||||
}
|
||||
|
||||
static inline int security_inode_rmdir(struct inode *dir,
|
||||
- struct dentry *dentry)
|
||||
+ struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -184,7 +184,8 @@ static int cap_inode_mkdir(struct inode
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_rmdir(struct inode *inode, struct dentry *dentry)
|
||||
+static int cap_inode_rmdir(struct inode *inode, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -396,11 +396,12 @@ int security_inode_mkdir(struct inode *d
|
||||
return security_ops->inode_mkdir(dir, dentry, mnt, mode);
|
||||
}
|
||||
|
||||
-int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
+int security_inode_rmdir(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return 0;
|
||||
- return security_ops->inode_rmdir(dir, dentry);
|
||||
+ return security_ops->inode_rmdir(dir, dentry, mnt);
|
||||
}
|
||||
|
||||
int security_inode_mknod(struct inode *dir, struct dentry *dentry,
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2609,7 +2609,8 @@ static int selinux_inode_mkdir(struct in
|
||||
return may_create(dir, dentry, SECCLASS_DIR);
|
||||
}
|
||||
|
||||
-static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
+static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
return may_link(dir, dentry, MAY_RMDIR);
|
||||
}
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -480,11 +480,13 @@ static int smack_inode_unlink(struct ino
|
||||
* smack_inode_rmdir - Smack check on directory deletion
|
||||
* @dir: containing directory object
|
||||
* @dentry: directory to unlink
|
||||
+ * @mnt: vfsmount @dentry to unlink
|
||||
*
|
||||
* Returns 0 if current can write the containing directory
|
||||
* and the directory, error code otherwise
|
||||
*/
|
||||
-static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
+static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_setattr LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/attr.c | 4 ++--
|
||||
fs/fat/file.c | 2 +-
|
||||
include/linux/security.h | 10 +++++++---
|
||||
security/capability.c | 3 ++-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 5 +++--
|
||||
security/smack/smack_lsm.c | 3 ++-
|
||||
7 files changed, 20 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/fs/attr.c
|
||||
+++ b/fs/attr.c
|
||||
@@ -164,13 +164,13 @@ int notify_change(struct dentry *dentry,
|
||||
down_write(&dentry->d_inode->i_alloc_sem);
|
||||
|
||||
if (inode->i_op && inode->i_op->setattr) {
|
||||
- error = security_inode_setattr(dentry, attr);
|
||||
+ error = security_inode_setattr(dentry, mnt, attr);
|
||||
if (!error)
|
||||
error = inode->i_op->setattr(dentry, attr);
|
||||
} else {
|
||||
error = inode_change_ok(inode, attr);
|
||||
if (!error)
|
||||
- error = security_inode_setattr(dentry, attr);
|
||||
+ error = security_inode_setattr(dentry, mnt, attr);
|
||||
if (!error) {
|
||||
if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
|
||||
(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
|
||||
--- a/fs/fat/file.c
|
||||
+++ b/fs/fat/file.c
|
||||
@@ -98,7 +98,7 @@ int fat_generic_ioctl(struct inode *inod
|
||||
* out the RO attribute for checking by the security
|
||||
* module, just because it maps to a file mode.
|
||||
*/
|
||||
- err = security_inode_setattr(filp->f_path.dentry, &ia);
|
||||
+ err = security_inode_setattr(filp->f_path.dentry, filp->f_path.mnt, &ia);
|
||||
if (err)
|
||||
goto up;
|
||||
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -412,6 +412,7 @@ static inline void security_free_mnt_opt
|
||||
* file attributes change (such as when a file is truncated, chown/chmod
|
||||
* operations, transferring disk quotas, etc).
|
||||
* @dentry contains the dentry structure for the file.
|
||||
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
|
||||
* @attr is the iattr structure containing the new file attributes.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_getattr:
|
||||
@@ -1371,7 +1372,8 @@ struct security_operations {
|
||||
int (*inode_readlink) (struct dentry *dentry);
|
||||
int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
|
||||
int (*inode_permission) (struct inode *inode, int mask);
|
||||
- int (*inode_setattr) (struct dentry *dentry, struct iattr *attr);
|
||||
+ int (*inode_setattr) (struct dentry *dentry, struct vfsmount *,
|
||||
+ struct iattr *attr);
|
||||
int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
|
||||
void (*inode_delete) (struct inode *inode);
|
||||
int (*inode_setxattr) (struct dentry *dentry, const char *name,
|
||||
@@ -1638,7 +1640,8 @@ int security_inode_rename(struct inode *
|
||||
int security_inode_readlink(struct dentry *dentry);
|
||||
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
|
||||
int security_inode_permission(struct inode *inode, int mask);
|
||||
-int security_inode_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
+int security_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct iattr *attr);
|
||||
int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry);
|
||||
void security_inode_delete(struct inode *inode);
|
||||
int security_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
@@ -2041,7 +2044,8 @@ static inline int security_inode_permiss
|
||||
}
|
||||
|
||||
static inline int security_inode_setattr(struct dentry *dentry,
|
||||
- struct iattr *attr)
|
||||
+ struct vfsmount *mnt,
|
||||
+ struct iattr *attr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -216,7 +216,8 @@ static int cap_inode_permission(struct i
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
+static int cap_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct iattr *iattr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -438,11 +438,12 @@ int security_inode_permission(struct ino
|
||||
return security_ops->inode_permission(inode, mask);
|
||||
}
|
||||
|
||||
-int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
+int security_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct iattr *attr)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return 0;
|
||||
- return security_ops->inode_setattr(dentry, attr);
|
||||
+ return security_ops->inode_setattr(dentry, mnt, attr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(security_inode_setattr);
|
||||
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2656,11 +2656,12 @@ static int selinux_inode_permission(stru
|
||||
open_file_mask_to_av(inode->i_mode, mask), NULL);
|
||||
}
|
||||
|
||||
-static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
+static int selinux_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct iattr *iattr)
|
||||
{
|
||||
int rc;
|
||||
|
||||
- rc = secondary_ops->inode_setattr(dentry, iattr);
|
||||
+ rc = secondary_ops->inode_setattr(dentry, mnt, iattr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -559,7 +559,8 @@ static int smack_inode_permission(struct
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
-static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
+static int smack_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct iattr *iattr)
|
||||
{
|
||||
/*
|
||||
* Need to allow for clearing the setuid bit.
|
||||
@@ -1,256 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_setxattr LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/xattr.c | 4 ++--
|
||||
include/linux/security.h | 41 ++++++++++++++++++++++++++---------------
|
||||
security/capability.c | 3 ++-
|
||||
security/commoncap.c | 5 +++--
|
||||
security/security.c | 16 ++++++++++------
|
||||
security/selinux/hooks.c | 8 +++++---
|
||||
security/smack/smack_lsm.c | 12 ++++++++----
|
||||
7 files changed, 56 insertions(+), 33 deletions(-)
|
||||
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -78,7 +78,7 @@ vfs_setxattr(struct dentry *dentry, stru
|
||||
return error;
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
- error = security_inode_setxattr(dentry, name, value, size, flags);
|
||||
+ error = security_inode_setxattr(dentry, mnt, name, value, size, flags);
|
||||
if (error)
|
||||
goto out;
|
||||
error = -EOPNOTSUPP;
|
||||
@@ -86,7 +86,7 @@ vfs_setxattr(struct dentry *dentry, stru
|
||||
error = inode->i_op->setxattr(dentry, name, value, size, flags);
|
||||
if (!error) {
|
||||
fsnotify_xattr(dentry);
|
||||
- security_inode_post_setxattr(dentry, name, value,
|
||||
+ security_inode_post_setxattr(dentry, mnt, name, value,
|
||||
size, flags);
|
||||
}
|
||||
} else if (!strncmp(name, XATTR_SECURITY_PREFIX,
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -54,8 +54,9 @@ extern void cap_capset_set(struct task_s
|
||||
extern int cap_bprm_set_security(struct linux_binprm *bprm);
|
||||
extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
|
||||
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
|
||||
-extern int cap_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags);
|
||||
+extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value, size_t size,
|
||||
+ int flags);
|
||||
extern int cap_inode_removexattr(struct dentry *dentry, const char *name);
|
||||
extern int cap_inode_need_killpriv(struct dentry *dentry);
|
||||
extern int cap_inode_killpriv(struct dentry *dentry);
|
||||
@@ -438,11 +439,11 @@ static inline void security_free_mnt_opt
|
||||
* inode.
|
||||
* @inode_setxattr:
|
||||
* Check permission before setting the extended attributes
|
||||
- * @value identified by @name for @dentry.
|
||||
+ * @value identified by @name for @dentry and @mnt.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_post_setxattr:
|
||||
* Update inode security field after successful setxattr operation.
|
||||
- * @value identified by @name for @dentry.
|
||||
+ * @value identified by @name for @dentry and @mnt.
|
||||
* @inode_getxattr:
|
||||
* Check permission before obtaining the extended attributes
|
||||
* identified by @name for @dentry.
|
||||
@@ -1392,10 +1393,13 @@ struct security_operations {
|
||||
struct iattr *attr);
|
||||
int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
|
||||
void (*inode_delete) (struct inode *inode);
|
||||
- int (*inode_setxattr) (struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags);
|
||||
- void (*inode_post_setxattr) (struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags);
|
||||
+ int (*inode_setxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value, size_t size,
|
||||
+ int flags);
|
||||
+ void (*inode_post_setxattr) (struct dentry *dentry,
|
||||
+ struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags);
|
||||
int (*inode_getxattr) (struct dentry *dentry, const char *name);
|
||||
int (*inode_listxattr) (struct dentry *dentry);
|
||||
int (*inode_removexattr) (struct dentry *dentry, const char *name);
|
||||
@@ -1666,10 +1670,12 @@ int security_inode_setattr(struct dentry
|
||||
struct iattr *attr);
|
||||
int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry);
|
||||
void security_inode_delete(struct inode *inode);
|
||||
-int security_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags);
|
||||
-void security_inode_post_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags);
|
||||
+int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags);
|
||||
+void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags);
|
||||
int security_inode_getxattr(struct dentry *dentry, const char *name);
|
||||
int security_inode_listxattr(struct dentry *dentry);
|
||||
int security_inode_removexattr(struct dentry *dentry, const char *name);
|
||||
@@ -2092,13 +2098,18 @@ static inline void security_inode_delete
|
||||
{ }
|
||||
|
||||
static inline int security_inode_setxattr(struct dentry *dentry,
|
||||
- const char *name, const void *value, size_t size, int flags)
|
||||
+ struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags)
|
||||
{
|
||||
- return cap_inode_setxattr(dentry, name, value, size, flags);
|
||||
+ return cap_inode_setxattr(dentry, mnt, name, value, size, flags);
|
||||
}
|
||||
|
||||
static inline void security_inode_post_setxattr(struct dentry *dentry,
|
||||
- const char *name, const void *value, size_t size, int flags)
|
||||
+ struct vfsmount *mnt,
|
||||
+ const char *name,
|
||||
+ const void *value,
|
||||
+ size_t size, int flags)
|
||||
{ }
|
||||
|
||||
static inline int security_inode_getxattr(struct dentry *dentry,
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -235,7 +235,8 @@ static void cap_inode_delete(struct inod
|
||||
{
|
||||
}
|
||||
|
||||
-static void cap_inode_post_setxattr(struct dentry *dentry, const char *name,
|
||||
+static void cap_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
}
|
||||
--- a/security/commoncap.c
|
||||
+++ b/security/commoncap.c
|
||||
@@ -414,8 +414,9 @@ int cap_bprm_secureexec (struct linux_bi
|
||||
current->egid != current->gid);
|
||||
}
|
||||
|
||||
-int cap_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags)
|
||||
+int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value, size_t size,
|
||||
+ int flags)
|
||||
{
|
||||
if (!strcmp(name, XATTR_NAME_CAPS)) {
|
||||
if (!capable(CAP_SETFCAP))
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -468,20 +468,24 @@ void security_inode_delete(struct inode
|
||||
security_ops->inode_delete(inode);
|
||||
}
|
||||
|
||||
-int security_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags)
|
||||
+int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value, size_t size,
|
||||
+ int flags)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return 0;
|
||||
- return security_ops->inode_setxattr(dentry, name, value, size, flags);
|
||||
+ return security_ops->inode_setxattr(dentry, mnt, name, value, size,
|
||||
+ flags);
|
||||
}
|
||||
|
||||
-void security_inode_post_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags)
|
||||
+void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return;
|
||||
- security_ops->inode_post_setxattr(dentry, name, value, size, flags);
|
||||
+ security_ops->inode_post_setxattr(dentry, mnt, name, value, size,
|
||||
+ flags);
|
||||
}
|
||||
|
||||
int security_inode_getxattr(struct dentry *dentry, const char *name)
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2713,8 +2713,9 @@ static int selinux_inode_setotherxattr(s
|
||||
return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
|
||||
}
|
||||
|
||||
-static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags)
|
||||
+static int selinux_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags)
|
||||
{
|
||||
struct task_security_struct *tsec = current->security;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
@@ -2768,7 +2769,8 @@ static int selinux_inode_setxattr(struct
|
||||
&ad);
|
||||
}
|
||||
|
||||
-static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
|
||||
+static void selinux_inode_post_setxattr(struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, const char *name,
|
||||
const void *value, size_t size,
|
||||
int flags)
|
||||
{
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -595,6 +595,7 @@ static int smack_inode_getattr(struct vf
|
||||
/**
|
||||
* smack_inode_setxattr - Smack check for setting xattrs
|
||||
* @dentry: the object
|
||||
+ * @mnt: unused
|
||||
* @name: name of the attribute
|
||||
* @value: unused
|
||||
* @size: unused
|
||||
@@ -604,8 +605,9 @@ static int smack_inode_getattr(struct vf
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
-static int smack_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags)
|
||||
+static int smack_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@@ -617,7 +619,7 @@ static int smack_inode_setxattr(struct d
|
||||
if (size == 0)
|
||||
rc = -EINVAL;
|
||||
} else
|
||||
- rc = cap_inode_setxattr(dentry, name, value, size, flags);
|
||||
+ rc = cap_inode_setxattr(dentry, mnt, name, value, size, flags);
|
||||
|
||||
if (rc == 0)
|
||||
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
|
||||
@@ -628,6 +630,7 @@ static int smack_inode_setxattr(struct d
|
||||
/**
|
||||
* smack_inode_post_setxattr - Apply the Smack update approved above
|
||||
* @dentry: object
|
||||
+ * @mnt: unused
|
||||
* @name: attribute name
|
||||
* @value: attribute value
|
||||
* @size: attribute size
|
||||
@@ -636,7 +639,8 @@ static int smack_inode_setxattr(struct d
|
||||
* Set the pointer in the inode blob to the entry found
|
||||
* in the master label list.
|
||||
*/
|
||||
-static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
|
||||
+static void smack_inode_post_setxattr(struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
struct inode_smack *isp;
|
||||
@@ -1,105 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_symlink LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/namei.c | 2 +-
|
||||
include/linux/security.h | 8 +++++---
|
||||
security/capability.c | 2 +-
|
||||
security/security.c | 4 ++--
|
||||
security/selinux/hooks.c | 3 ++-
|
||||
5 files changed, 11 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2358,7 +2358,7 @@ int vfs_symlink(struct inode *dir, struc
|
||||
if (!dir->i_op || !dir->i_op->symlink)
|
||||
return -EPERM;
|
||||
|
||||
- error = security_inode_symlink(dir, dentry, oldname);
|
||||
+ error = security_inode_symlink(dir, dentry, mnt, oldname);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -355,6 +355,7 @@ static inline void security_free_mnt_opt
|
||||
* Check the permission to create a symbolic link to a file.
|
||||
* @dir contains the inode structure of parent directory of the symbolic link.
|
||||
* @dentry contains the dentry structure of the symbolic link.
|
||||
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
|
||||
* @old_name contains the pathname of file.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_mkdir:
|
||||
@@ -1363,8 +1364,8 @@ struct security_operations {
|
||||
int (*inode_link) (struct dentry *old_dentry,
|
||||
struct inode *dir, struct dentry *new_dentry);
|
||||
int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
|
||||
- int (*inode_symlink) (struct inode *dir,
|
||||
- struct dentry *dentry, const char *old_name);
|
||||
+ int (*inode_symlink) (struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, const char *old_name);
|
||||
int (*inode_mkdir) (struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, int mode);
|
||||
int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
|
||||
@@ -1634,7 +1635,7 @@ int security_inode_link(struct dentry *o
|
||||
struct dentry *new_dentry);
|
||||
int security_inode_unlink(struct inode *dir, struct dentry *dentry);
|
||||
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
|
||||
- const char *old_name);
|
||||
+ struct vfsmount *mnt, const char *old_name);
|
||||
int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, int mode);
|
||||
int security_inode_rmdir(struct inode *dir, struct dentry *dentry);
|
||||
@@ -1999,6 +2000,7 @@ static inline int security_inode_unlink(
|
||||
|
||||
static inline int security_inode_symlink(struct inode *dir,
|
||||
struct dentry *dentry,
|
||||
+ struct vfsmount *mnt,
|
||||
const char *old_name)
|
||||
{
|
||||
return 0;
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -172,7 +172,7 @@ static int cap_inode_unlink(struct inode
|
||||
}
|
||||
|
||||
static int cap_inode_symlink(struct inode *inode, struct dentry *dentry,
|
||||
- const char *name)
|
||||
+ struct vfsmount *mnt, const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -379,11 +379,11 @@ int security_inode_unlink(struct inode *
|
||||
}
|
||||
|
||||
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
|
||||
- const char *old_name)
|
||||
+ struct vfsmount *mnt, const char *old_name)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dir)))
|
||||
return 0;
|
||||
- return security_ops->inode_symlink(dir, dentry, old_name);
|
||||
+ return security_ops->inode_symlink(dir, dentry, mnt, old_name);
|
||||
}
|
||||
|
||||
int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2592,7 +2592,8 @@ static int selinux_inode_unlink(struct i
|
||||
return may_link(dir, dentry, MAY_UNLINK);
|
||||
}
|
||||
|
||||
-static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
|
||||
+static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, const char *name)
|
||||
{
|
||||
return may_create(dir, dentry, SECCLASS_LNK_FILE);
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Pass struct vfsmount to the inode_unlink LSM hook
|
||||
|
||||
This is needed for computing pathnames in the AppArmor LSM.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/namei.c | 2 +-
|
||||
include/linux/security.h | 10 +++++++---
|
||||
security/capability.c | 3 ++-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 5 +++--
|
||||
security/smack/smack_lsm.c | 4 +++-
|
||||
6 files changed, 19 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2264,7 +2264,7 @@ int vfs_unlink(struct inode *dir, struct
|
||||
if (d_mountpoint(dentry))
|
||||
error = -EBUSY;
|
||||
else {
|
||||
- error = security_inode_unlink(dir, dentry);
|
||||
+ error = security_inode_unlink(dir, dentry, mnt);
|
||||
if (!error)
|
||||
error = dir->i_op->unlink(dir, dentry);
|
||||
}
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -352,6 +352,7 @@ static inline void security_free_mnt_opt
|
||||
* Check the permission to remove a hard link to a file.
|
||||
* @dir contains the inode structure of parent directory of the file.
|
||||
* @dentry contains the dentry structure for file to be unlinked.
|
||||
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_symlink:
|
||||
* Check the permission to create a symbolic link to a file.
|
||||
@@ -1368,7 +1369,8 @@ struct security_operations {
|
||||
int (*inode_link) (struct dentry *old_dentry, struct vfsmount *old_mnt,
|
||||
struct inode *dir, struct dentry *new_dentry,
|
||||
struct vfsmount *new_mnt);
|
||||
- int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
|
||||
+ int (*inode_unlink) (struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt);
|
||||
int (*inode_symlink) (struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, const char *old_name);
|
||||
int (*inode_mkdir) (struct inode *dir, struct dentry *dentry,
|
||||
@@ -1640,7 +1642,8 @@ int security_inode_create(struct inode *
|
||||
int security_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt,
|
||||
struct inode *dir, struct dentry *new_dentry,
|
||||
struct vfsmount *new_mnt);
|
||||
-int security_inode_unlink(struct inode *dir, struct dentry *dentry);
|
||||
+int security_inode_unlink(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt);
|
||||
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
|
||||
struct vfsmount *mnt, const char *old_name);
|
||||
int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
@@ -2003,7 +2006,8 @@ static inline int security_inode_link(st
|
||||
}
|
||||
|
||||
static inline int security_inode_unlink(struct inode *dir,
|
||||
- struct dentry *dentry)
|
||||
+ struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -167,7 +167,8 @@ static int cap_inode_link(struct dentry
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_unlink(struct inode *inode, struct dentry *dentry)
|
||||
+static int cap_inode_unlink(struct inode *inode, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -373,11 +373,12 @@ int security_inode_link(struct dentry *o
|
||||
new_dentry, new_mnt);
|
||||
}
|
||||
|
||||
-int security_inode_unlink(struct inode *dir, struct dentry *dentry)
|
||||
+int security_inode_unlink(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return 0;
|
||||
- return security_ops->inode_unlink(dir, dentry);
|
||||
+ return security_ops->inode_unlink(dir, dentry, mnt);
|
||||
}
|
||||
|
||||
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2587,11 +2587,12 @@ static int selinux_inode_link(struct den
|
||||
return may_link(dir, old_dentry, MAY_LINK);
|
||||
}
|
||||
|
||||
-static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
|
||||
+static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
int rc;
|
||||
|
||||
- rc = secondary_ops->inode_unlink(dir, dentry);
|
||||
+ rc = secondary_ops->inode_unlink(dir, dentry, mnt);
|
||||
if (rc)
|
||||
return rc;
|
||||
return may_link(dir, dentry, MAY_UNLINK);
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -454,11 +454,13 @@ static int smack_inode_link(struct dentr
|
||||
* smack_inode_unlink - Smack check on inode deletion
|
||||
* @dir: containing directory object
|
||||
* @dentry: file to unlink
|
||||
+ * @mnt: vfsmount of file to unlink
|
||||
*
|
||||
* Returns 0 if current can write the containing directory
|
||||
* and the object, error code otherwise
|
||||
*/
|
||||
-static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
|
||||
+static int smack_inode_unlink(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
struct inode *ip = dentry->d_inode;
|
||||
int rc;
|
||||
@@ -1,608 +0,0 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: Pass struct file down the inode_*xattr security LSM hooks
|
||||
|
||||
This allows LSMs to also distinguish between file descriptor and path
|
||||
access for the xattr operations. (The other relevant operations are
|
||||
covered by the setattr hook.)
|
||||
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/xattr.c | 59 +++++++++++++++++++++++----------------------
|
||||
include/linux/security.h | 38 ++++++++++++++++------------
|
||||
include/linux/xattr.h | 9 +++---
|
||||
security/capability.c | 5 ++-
|
||||
security/commoncap.c | 4 +--
|
||||
security/security.c | 17 ++++++------
|
||||
security/selinux/hooks.c | 10 ++++---
|
||||
security/smack/smack_lsm.c | 14 ++++++----
|
||||
8 files changed, 87 insertions(+), 69 deletions(-)
|
||||
|
||||
Index: linux-2.6.27/fs/xattr.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/fs/xattr.c
|
||||
+++ linux-2.6.27/fs/xattr.c
|
||||
@@ -68,7 +68,7 @@ xattr_permission(struct inode *inode, co
|
||||
|
||||
int
|
||||
vfs_setxattr(struct dentry *dentry, struct vfsmount *mnt, const char *name,
|
||||
- const void *value, size_t size, int flags)
|
||||
+ const void *value, size_t size, int flags, struct file *file)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -78,7 +78,7 @@ vfs_setxattr(struct dentry *dentry, stru
|
||||
return error;
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
- error = security_inode_setxattr(dentry, mnt, name, value, size, flags);
|
||||
+ error = security_inode_setxattr(dentry, mnt, name, value, size, flags, file);
|
||||
if (error)
|
||||
goto out;
|
||||
error = -EOPNOTSUPP;
|
||||
@@ -132,7 +132,7 @@ EXPORT_SYMBOL_GPL(xattr_getsecurity);
|
||||
|
||||
ssize_t
|
||||
vfs_getxattr(struct dentry *dentry, struct vfsmount *mnt, const char *name,
|
||||
- void *value, size_t size)
|
||||
+ void *value, size_t size, struct file *file)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -141,7 +141,7 @@ vfs_getxattr(struct dentry *dentry, stru
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
- error = security_inode_getxattr(dentry, mnt, name);
|
||||
+ error = security_inode_getxattr(dentry, mnt, name, file);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@@ -169,12 +169,12 @@ EXPORT_SYMBOL_GPL(vfs_getxattr);
|
||||
|
||||
ssize_t
|
||||
vfs_listxattr(struct dentry *dentry, struct vfsmount *mnt, char *list,
|
||||
- size_t size)
|
||||
+ size_t size, struct file *file)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
ssize_t error;
|
||||
|
||||
- error = security_inode_listxattr(dentry, mnt);
|
||||
+ error = security_inode_listxattr(dentry, mnt, file);
|
||||
if (error)
|
||||
return error;
|
||||
error = -EOPNOTSUPP;
|
||||
@@ -190,7 +190,8 @@ vfs_listxattr(struct dentry *dentry, str
|
||||
EXPORT_SYMBOL_GPL(vfs_listxattr);
|
||||
|
||||
int
|
||||
-vfs_removexattr(struct dentry *dentry, struct vfsmount *mnt, const char *name)
|
||||
+vfs_removexattr(struct dentry *dentry, struct vfsmount *mnt, const char *name,
|
||||
+ struct file *file)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -202,7 +203,7 @@ vfs_removexattr(struct dentry *dentry, s
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
- error = security_inode_removexattr(dentry, mnt, name);
|
||||
+ error = security_inode_removexattr(dentry, mnt, name, file);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@@ -222,7 +223,7 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
|
||||
*/
|
||||
static long
|
||||
setxattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name,
|
||||
- const void __user *value, size_t size, int flags)
|
||||
+ const void __user *value, size_t size, int flags, struct file *file)
|
||||
{
|
||||
int error;
|
||||
void *kvalue = NULL;
|
||||
@@ -249,7 +250,7 @@ setxattr(struct dentry *dentry, struct v
|
||||
}
|
||||
}
|
||||
|
||||
- error = vfs_setxattr(dentry, mnt, kname, kvalue, size, flags);
|
||||
+ error = vfs_setxattr(dentry, mnt, kname, kvalue, size, flags, file);
|
||||
kfree(kvalue);
|
||||
return error;
|
||||
}
|
||||
@@ -266,7 +267,7 @@ SYSCALL_DEFINE5(setxattr, const char __u
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = setxattr(path.dentry, path.mnt, name, value, size, flags);
|
||||
+ error = setxattr(path.dentry, path.mnt, name, value, size, flags, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -285,7 +286,7 @@ SYSCALL_DEFINE5(lsetxattr, const char __
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = setxattr(path.dentry, path.mnt, name, value, size, flags);
|
||||
+ error = setxattr(path.dentry, path.mnt, name, value, size, flags, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -306,7 +307,8 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, cons
|
||||
audit_inode(NULL, dentry);
|
||||
error = mnt_want_write_file(f->f_path.mnt, f);
|
||||
if (!error) {
|
||||
- error = setxattr(dentry, f->f_vfsmnt, name, value, size, flags);
|
||||
+ error = setxattr(dentry, f->f_vfsmnt, name, value, size, flags,
|
||||
+ f);
|
||||
mnt_drop_write(f->f_path.mnt);
|
||||
}
|
||||
fput(f);
|
||||
@@ -318,7 +320,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, cons
|
||||
*/
|
||||
static ssize_t
|
||||
getxattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name,
|
||||
- void __user *value, size_t size)
|
||||
+ void __user *value, size_t size, struct file *file)
|
||||
{
|
||||
ssize_t error;
|
||||
void *kvalue = NULL;
|
||||
@@ -338,7 +340,7 @@ getxattr(struct dentry *dentry, struct v
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
- error = vfs_getxattr(dentry, mnt, kname, kvalue, size);
|
||||
+ error = vfs_getxattr(dentry, mnt, kname, kvalue, size, file);
|
||||
if (error > 0) {
|
||||
if (size && copy_to_user(value, kvalue, error))
|
||||
error = -EFAULT;
|
||||
@@ -360,7 +362,7 @@ SYSCALL_DEFINE4(getxattr, const char __u
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = getxattr(path.dentry, path.mnt, name, value, size);
|
||||
+ error = getxattr(path.dentry, path.mnt, name, value, size, NULL);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -374,7 +376,7 @@ SYSCALL_DEFINE4(lgetxattr, const char __
|
||||
error = user_lpath(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = getxattr(path.dentry, path.mnt, name, value, size);
|
||||
+ error = getxattr(path.dentry, path.mnt, name, value, size, NULL);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -389,7 +391,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, cons
|
||||
if (!f)
|
||||
return error;
|
||||
audit_inode(NULL, f->f_path.dentry);
|
||||
- error = getxattr(f->f_path.dentry, f->f_path.mnt, name, value, size);
|
||||
+ error = getxattr(f->f_path.dentry, f->f_path.mnt, name, value, size, f);
|
||||
fput(f);
|
||||
return error;
|
||||
}
|
||||
@@ -399,7 +401,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, cons
|
||||
*/
|
||||
static ssize_t
|
||||
listxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *list,
|
||||
- size_t size)
|
||||
+ size_t size, struct file *file)
|
||||
{
|
||||
ssize_t error;
|
||||
char *klist = NULL;
|
||||
@@ -412,7 +414,7 @@ listxattr(struct dentry *dentry, struct
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
- error = vfs_listxattr(dentry, mnt, klist, size);
|
||||
+ error = vfs_listxattr(dentry, mnt, klist, size, file);
|
||||
if (error > 0) {
|
||||
if (size && copy_to_user(list, klist, error))
|
||||
error = -EFAULT;
|
||||
@@ -434,7 +436,7 @@ SYSCALL_DEFINE3(listxattr, const char __
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = listxattr(path.dentry, path.mnt, list, size);
|
||||
+ error = listxattr(path.dentry, path.mnt, list, size, NULL);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -448,7 +450,7 @@ SYSCALL_DEFINE3(llistxattr, const char _
|
||||
error = user_lpath(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = listxattr(path.dentry, path.mnt, list, size);
|
||||
+ error = listxattr(path.dentry, path.mnt, list, size, NULL);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -462,7 +464,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, cha
|
||||
if (!f)
|
||||
return error;
|
||||
audit_inode(NULL, f->f_path.dentry);
|
||||
- error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size);
|
||||
+ error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size, f);
|
||||
fput(f);
|
||||
return error;
|
||||
}
|
||||
@@ -471,7 +473,8 @@ SYSCALL_DEFINE3(flistxattr, int, fd, cha
|
||||
* Extended attribute REMOVE operations
|
||||
*/
|
||||
static long
|
||||
-removexattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name)
|
||||
+removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char __user *name, struct file *file)
|
||||
{
|
||||
int error;
|
||||
char kname[XATTR_NAME_MAX + 1];
|
||||
@@ -482,7 +485,7 @@ removexattr(struct dentry *dentry, struc
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
- return vfs_removexattr(dentry, mnt, kname);
|
||||
+ return vfs_removexattr(dentry, mnt, kname, file);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
|
||||
@@ -496,7 +499,7 @@ SYSCALL_DEFINE2(removexattr, const char
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = removexattr(path.dentry, path.mnt, name);
|
||||
+ error = removexattr(path.dentry, path.mnt, name, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -514,7 +517,7 @@ SYSCALL_DEFINE2(lremovexattr, const char
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = removexattr(path.dentry, path.mnt, name);
|
||||
+ error = removexattr(path.dentry, path.mnt, name, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -534,7 +537,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, c
|
||||
audit_inode(NULL, dentry);
|
||||
error = mnt_want_write_file(f->f_path.mnt, f);
|
||||
if (!error) {
|
||||
- error = removexattr(dentry, f->f_path.mnt, name);
|
||||
+ error = removexattr(dentry, f->f_path.mnt, name, f);
|
||||
mnt_drop_write(f->f_path.mnt);
|
||||
}
|
||||
fput(f);
|
||||
Index: linux-2.6.27/include/linux/security.h
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/include/linux/security.h
|
||||
+++ linux-2.6.27/include/linux/security.h
|
||||
@@ -56,9 +56,9 @@ extern void cap_bprm_apply_creds(struct
|
||||
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
|
||||
extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value, size_t size,
|
||||
- int flags);
|
||||
+ int flags, struct file *file);
|
||||
extern int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name);
|
||||
+ const char *name, struct file *file);
|
||||
extern int cap_inode_need_killpriv(struct dentry *dentry);
|
||||
extern int cap_inode_killpriv(struct dentry *dentry);
|
||||
extern int cap_task_post_setuid(uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
|
||||
@@ -1396,16 +1396,17 @@ struct security_operations {
|
||||
void (*inode_delete) (struct inode *inode);
|
||||
int (*inode_setxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value, size_t size,
|
||||
- int flags);
|
||||
+ int flags, struct file *file);
|
||||
void (*inode_post_setxattr) (struct dentry *dentry,
|
||||
struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name);
|
||||
- int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt);
|
||||
+ const char *name, struct file *file);
|
||||
+ int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct file *file);
|
||||
int (*inode_removexattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name);
|
||||
+ const char *name, struct file *file);
|
||||
int (*inode_need_killpriv) (struct dentry *dentry);
|
||||
int (*inode_killpriv) (struct dentry *dentry);
|
||||
int (*inode_getsecurity) (const struct inode *inode, const char *name, void **buffer, bool alloc);
|
||||
@@ -1675,15 +1676,16 @@ int security_inode_getattr(struct vfsmou
|
||||
void security_inode_delete(struct inode *inode);
|
||||
int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
- size_t size, int flags);
|
||||
+ size_t size, int flags, struct file *file);
|
||||
void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name);
|
||||
-int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt);
|
||||
+ const char *name, struct file *file);
|
||||
+int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct file *file);
|
||||
int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name);
|
||||
+ const char *name, struct file *file);
|
||||
int security_inode_need_killpriv(struct dentry *dentry);
|
||||
int security_inode_killpriv(struct dentry *dentry);
|
||||
int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc);
|
||||
@@ -2105,9 +2107,10 @@ static inline void security_inode_delete
|
||||
static inline int security_inode_setxattr(struct dentry *dentry,
|
||||
struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
- size_t size, int flags)
|
||||
+ size_t size, int flags,
|
||||
+ struct file *file)
|
||||
{
|
||||
- return cap_inode_setxattr(dentry, mnt, name, value, size, flags);
|
||||
+ return cap_inode_setxattr(dentry, mnt, name, value, size, flags, file);
|
||||
}
|
||||
|
||||
static inline void security_inode_post_setxattr(struct dentry *dentry,
|
||||
@@ -2119,22 +2122,25 @@ static inline void security_inode_post_s
|
||||
|
||||
static inline int security_inode_getxattr(struct dentry *dentry,
|
||||
struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name,
|
||||
+ struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_inode_listxattr(struct dentry *dentry,
|
||||
- struct vfsmount *mnt)
|
||||
+ struct vfsmount *mnt,
|
||||
+ struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_inode_removexattr(struct dentry *dentry,
|
||||
struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name,
|
||||
+ struct file *file)
|
||||
{
|
||||
- return cap_inode_removexattr(dentry, mnt, name);
|
||||
+ return cap_inode_removexattr(dentry, mnt, name, file);
|
||||
}
|
||||
|
||||
static inline int security_inode_need_killpriv(struct dentry *dentry)
|
||||
Index: linux-2.6.27/include/linux/xattr.h
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/include/linux/xattr.h
|
||||
+++ linux-2.6.27/include/linux/xattr.h
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mount.h>
|
||||
+#include <linux/fs.h>
|
||||
|
||||
/* Namespaces */
|
||||
#define XATTR_OS2_PREFIX "os2."
|
||||
@@ -48,10 +49,10 @@ struct xattr_handler {
|
||||
};
|
||||
|
||||
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
|
||||
-ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, const char *, void *, size_t);
|
||||
-ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list, size_t size);
|
||||
-int vfs_setxattr(struct dentry *, struct vfsmount *, const char *, const void *, size_t, int);
|
||||
-int vfs_removexattr(struct dentry *, struct vfsmount *mnt, const char *);
|
||||
+ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, const char *, void *, size_t, struct file *file);
|
||||
+ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list, size_t size, struct file *file);
|
||||
+int vfs_setxattr(struct dentry *, struct vfsmount *, const char *, const void *, size_t, int, struct file *file);
|
||||
+int vfs_removexattr(struct dentry *, struct vfsmount *mnt, const char *, struct file *file);
|
||||
|
||||
ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size);
|
||||
ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
|
||||
Index: linux-2.6.27/security/capability.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/security/capability.c
|
||||
+++ linux-2.6.27/security/capability.c
|
||||
@@ -242,12 +242,13 @@ static void cap_inode_post_setxattr(stru
|
||||
}
|
||||
|
||||
static int cap_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name, struct file *f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
|
||||
+static int cap_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct file *f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
Index: linux-2.6.27/security/commoncap.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/security/commoncap.c
|
||||
+++ linux-2.6.27/security/commoncap.c
|
||||
@@ -416,7 +416,7 @@ int cap_bprm_secureexec (struct linux_bi
|
||||
|
||||
int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value, size_t size,
|
||||
- int flags)
|
||||
+ int flags, struct file *file)
|
||||
{
|
||||
if (!strcmp(name, XATTR_NAME_CAPS)) {
|
||||
if (!capable(CAP_SETFCAP))
|
||||
@@ -430,7 +430,7 @@ int cap_inode_setxattr(struct dentry *de
|
||||
}
|
||||
|
||||
int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name, struct file *file)
|
||||
{
|
||||
if (!strcmp(name, XATTR_NAME_CAPS)) {
|
||||
if (!capable(CAP_SETFCAP))
|
||||
Index: linux-2.6.27/security/security.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/security/security.c
|
||||
+++ linux-2.6.27/security/security.c
|
||||
@@ -470,12 +470,12 @@ void security_inode_delete(struct inode
|
||||
|
||||
int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value, size_t size,
|
||||
- int flags)
|
||||
+ int flags, struct file *file)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return 0;
|
||||
return security_ops->inode_setxattr(dentry, mnt, name, value, size,
|
||||
- flags);
|
||||
+ flags, file);
|
||||
}
|
||||
|
||||
void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
@@ -489,26 +489,27 @@ void security_inode_post_setxattr(struct
|
||||
}
|
||||
|
||||
int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name, struct file *file)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return 0;
|
||||
- return security_ops->inode_getxattr(dentry, mnt, name);
|
||||
+ return security_ops->inode_getxattr(dentry, mnt, name, file);
|
||||
}
|
||||
|
||||
-int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
|
||||
+int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct file *file)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return 0;
|
||||
- return security_ops->inode_listxattr(dentry, mnt);
|
||||
+ return security_ops->inode_listxattr(dentry, mnt, file);
|
||||
}
|
||||
|
||||
int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name, struct file *file)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dentry->d_inode)))
|
||||
return 0;
|
||||
- return security_ops->inode_removexattr(dentry, mnt, name);
|
||||
+ return security_ops->inode_removexattr(dentry, mnt, name, file);
|
||||
}
|
||||
|
||||
int security_inode_need_killpriv(struct dentry *dentry)
|
||||
Index: linux-2.6.27/security/selinux/hooks.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/security/selinux/hooks.c
|
||||
+++ linux-2.6.27/security/selinux/hooks.c
|
||||
@@ -2715,7 +2715,7 @@ static int selinux_inode_setotherxattr(s
|
||||
|
||||
static int selinux_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
- size_t size, int flags)
|
||||
+ size_t size, int flags, struct file *file)
|
||||
{
|
||||
struct task_security_struct *tsec = current->security;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
@@ -2797,18 +2797,20 @@ static void selinux_inode_post_setxattr(
|
||||
}
|
||||
|
||||
static int selinux_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name, struct file *file)
|
||||
{
|
||||
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
|
||||
}
|
||||
|
||||
-static int selinux_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
|
||||
+static int selinux_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct file *file)
|
||||
{
|
||||
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
|
||||
}
|
||||
|
||||
static int selinux_inode_removexattr(struct dentry *dentry,
|
||||
- struct vfsmount *mnt, const char *name)
|
||||
+ struct vfsmount *mnt, const char *name,
|
||||
+ struct file *file)
|
||||
{
|
||||
if (strcmp(name, XATTR_NAME_SELINUX))
|
||||
return selinux_inode_setotherxattr(dentry, name);
|
||||
Index: linux-2.6.27/security/smack/smack_lsm.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/security/smack/smack_lsm.c
|
||||
+++ linux-2.6.27/security/smack/smack_lsm.c
|
||||
@@ -600,6 +600,7 @@ static int smack_inode_getattr(struct vf
|
||||
* @value: unused
|
||||
* @size: unused
|
||||
* @flags: unused
|
||||
+ * @file: unused
|
||||
*
|
||||
* This protects the Smack attribute explicitly.
|
||||
*
|
||||
@@ -607,7 +608,7 @@ static int smack_inode_getattr(struct vf
|
||||
*/
|
||||
static int smack_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
- size_t size, int flags)
|
||||
+ size_t size, int flags, struct file *file)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@@ -619,7 +620,8 @@ static int smack_inode_setxattr(struct d
|
||||
if (size == 0)
|
||||
rc = -EINVAL;
|
||||
} else
|
||||
- rc = cap_inode_setxattr(dentry, mnt, name, value, size, flags);
|
||||
+ rc = cap_inode_setxattr(dentry, mnt, name, value, size, flags,
|
||||
+ file);
|
||||
|
||||
if (rc == 0)
|
||||
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
|
||||
@@ -675,11 +677,12 @@ static void smack_inode_post_setxattr(st
|
||||
* @dentry: the object
|
||||
* @mnt: unused
|
||||
* @name: unused
|
||||
+ * @file: unused
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
static int smack_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name, struct file *file)
|
||||
{
|
||||
return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
|
||||
}
|
||||
@@ -689,13 +692,14 @@ static int smack_inode_getxattr(struct d
|
||||
* @dentry: the object
|
||||
* @mnt: unused
|
||||
* @name: name of the attribute
|
||||
+ * @file: unused
|
||||
*
|
||||
* Removing the Smack attribute requires CAP_MAC_ADMIN
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
static int smack_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name, struct file *file)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@@ -705,7 +709,7 @@ static int smack_inode_removexattr(struc
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
rc = -EPERM;
|
||||
} else
|
||||
- rc = cap_inode_removexattr(dentry, mnt, name);
|
||||
+ rc = cap_inode_removexattr(dentry, mnt, name, file);
|
||||
|
||||
if (rc == 0)
|
||||
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
|
||||
@@ -1,111 +0,0 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: Factor out sysctl pathname code
|
||||
|
||||
Convert the selinux sysctl pathname computation code into a standalone
|
||||
function.
|
||||
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
Reviewed-by: James Morris <jmorris@namei.org>
|
||||
|
||||
---
|
||||
include/linux/sysctl.h | 2 ++
|
||||
kernel/sysctl.c | 27 +++++++++++++++++++++++++++
|
||||
security/selinux/hooks.c | 34 +++++-----------------------------
|
||||
3 files changed, 34 insertions(+), 29 deletions(-)
|
||||
|
||||
--- a/include/linux/sysctl.h
|
||||
+++ b/include/linux/sysctl.h
|
||||
@@ -996,6 +996,8 @@ extern int proc_doulongvec_minmax(struct
|
||||
extern int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int,
|
||||
struct file *, void __user *, size_t *, loff_t *);
|
||||
|
||||
+extern char *sysctl_pathname(ctl_table *, char *, int);
|
||||
+
|
||||
extern int do_sysctl (int __user *name, int nlen,
|
||||
void __user *oldval, size_t __user *oldlenp,
|
||||
void __user *newval, size_t newlen);
|
||||
--- a/kernel/sysctl.c
|
||||
+++ b/kernel/sysctl.c
|
||||
@@ -1552,6 +1552,33 @@ void register_sysctl_root(struct ctl_tab
|
||||
spin_unlock(&sysctl_lock);
|
||||
}
|
||||
|
||||
+char *sysctl_pathname(struct ctl_table *table, char *buffer, int buflen)
|
||||
+{
|
||||
+ if (buflen < 1)
|
||||
+ return NULL;
|
||||
+ buffer += --buflen;
|
||||
+ *buffer = '\0';
|
||||
+
|
||||
+ while (table) {
|
||||
+ int namelen = strlen(table->procname);
|
||||
+
|
||||
+ if (buflen < namelen + 1)
|
||||
+ return NULL;
|
||||
+ buflen -= namelen + 1;
|
||||
+ buffer -= namelen;
|
||||
+ memcpy(buffer, table->procname, namelen);
|
||||
+ *--buffer = '/';
|
||||
+ table = table->parent;
|
||||
+ }
|
||||
+ if (buflen < 4)
|
||||
+ return NULL;
|
||||
+ buffer -= 4;
|
||||
+ memcpy(buffer, "/sys", 4);
|
||||
+
|
||||
+ return buffer;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(sysctl_pathname);
|
||||
+
|
||||
#ifdef CONFIG_SYSCTL_SYSCALL
|
||||
/* Perform the actual read/write of a sysctl table entry. */
|
||||
static int do_sysctl_strategy(struct ctl_table_root *root,
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -1811,40 +1811,16 @@ static int selinux_capable(struct task_s
|
||||
|
||||
static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
|
||||
{
|
||||
- int buflen, rc;
|
||||
- char *buffer, *path, *end;
|
||||
+ char *buffer, *path;
|
||||
+ int rc = -ENOMEM;
|
||||
|
||||
- rc = -ENOMEM;
|
||||
buffer = (char *)__get_free_page(GFP_KERNEL);
|
||||
if (!buffer)
|
||||
goto out;
|
||||
|
||||
- buflen = PAGE_SIZE;
|
||||
- end = buffer+buflen;
|
||||
- *--end = '\0';
|
||||
- buflen--;
|
||||
- path = end-1;
|
||||
- *path = '/';
|
||||
- while (table) {
|
||||
- const char *name = table->procname;
|
||||
- size_t namelen = strlen(name);
|
||||
- buflen -= namelen + 1;
|
||||
- if (buflen < 0)
|
||||
- goto out_free;
|
||||
- end -= namelen;
|
||||
- memcpy(end, name, namelen);
|
||||
- *--end = '/';
|
||||
- path = end;
|
||||
- table = table->parent;
|
||||
- }
|
||||
- buflen -= 4;
|
||||
- if (buflen < 0)
|
||||
- goto out_free;
|
||||
- end -= 4;
|
||||
- memcpy(end, "/sys", 4);
|
||||
- path = end;
|
||||
- rc = security_genfs_sid("proc", path, tclass, sid);
|
||||
-out_free:
|
||||
+ path = sysctl_pathname(table, buffer, PAGE_SIZE);
|
||||
+ if (path)
|
||||
+ rc = security_genfs_sid("proc", path, tclass, sid);
|
||||
free_page((unsigned long)buffer);
|
||||
out:
|
||||
return rc;
|
||||
@@ -1,267 +0,0 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: Fix __d_path() for lazy unmounts and make it unambiguous
|
||||
|
||||
First, when __d_path() hits a lazily unmounted mount point, it tries to prepend
|
||||
the name of the lazily unmounted dentry to the path name. It gets this wrong,
|
||||
and also overwrites the slash that separates the name from the following
|
||||
pathname component. This patch fixes that; if a process was in directory
|
||||
/foo/bar and /foo got lazily unmounted, the old result was ``foobar'' (note the
|
||||
missing slash), while the new result with this patch is ``foo/bar''.
|
||||
|
||||
Second, it isn't always possible to tell from the __d_path() result whether the
|
||||
specified root and rootmnt (i.e., the chroot) was reached. We need an
|
||||
unambiguous result for AppArmor at least though, so we make sure that paths
|
||||
will only start with a slash if the path leads all the way up to the root.
|
||||
|
||||
We also add a @fail_deleted argument, which allows to get rid of some of the
|
||||
mess in sys_getcwd().
|
||||
|
||||
This patch leaves getcwd() and d_path() as they were before for everything
|
||||
except for bind-mounted directories; for them, it reports ``/foo/bar'' instead
|
||||
of ``foobar'' in the example described above.
|
||||
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
Acked-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
|
||||
|
||||
[ Moved dcache_lock outside vfsmount_lock to fix lock order (bnc#490902) ]
|
||||
Signed-off-by: Nick Piggin <npiggin@suse.de>
|
||||
|
||||
---
|
||||
fs/dcache.c | 126 +++++++++++++++++++++++++++----------------------
|
||||
fs/seq_file.c | 4 -
|
||||
include/linux/dcache.h | 5 +
|
||||
3 files changed, 75 insertions(+), 60 deletions(-)
|
||||
|
||||
Index: linux-2.6.27/fs/dcache.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/fs/dcache.c
|
||||
+++ linux-2.6.27/fs/dcache.c
|
||||
@@ -1898,44 +1898,46 @@ static int prepend_name(char **buffer, i
|
||||
* @root: root vfsmnt/dentry (may be modified by this function)
|
||||
* @buffer: buffer to return value in
|
||||
* @buflen: buffer length
|
||||
+ * @flags: flags controling behavior of d_path
|
||||
*
|
||||
- * Convert a dentry into an ASCII path name. If the entry has been deleted
|
||||
- * the string " (deleted)" is appended. Note that this is ambiguous.
|
||||
- *
|
||||
- * Returns the buffer or an error code if the path was too long.
|
||||
- *
|
||||
- * "buflen" should be positive. Caller holds the dcache_lock.
|
||||
+ * Convert a dentry into an ASCII path name. If the entry has been deleted,
|
||||
+ * then if @flags has D_PATH_FAIL_DELETED set, ERR_PTR(-ENOENT) is returned.
|
||||
+ * Otherwise, the string " (deleted)" is appended. Note that this is ambiguous.
|
||||
*
|
||||
* If path is not reachable from the supplied root, then the value of
|
||||
- * root is changed (without modifying refcounts).
|
||||
+ * root is changed (without modifying refcounts). The path returned in this
|
||||
+ * case will be relative (i.e., it will not start with a slash).
|
||||
+ *
|
||||
+ * Returns the buffer or an error code if the path was too long.
|
||||
*/
|
||||
char *__d_path(const struct path *path, struct path *root,
|
||||
- char *buffer, int buflen)
|
||||
+ char *buffer, int buflen, int flags)
|
||||
{
|
||||
struct dentry *dentry = path->dentry;
|
||||
struct vfsmount *vfsmnt = path->mnt;
|
||||
- char *end = buffer + buflen;
|
||||
- char *retval;
|
||||
+ const unsigned char *name;
|
||||
+ int namelen;
|
||||
+
|
||||
+ buffer += buflen;
|
||||
+ prepend(&buffer, &buflen, "\0", 1);
|
||||
|
||||
+ spin_lock(&dcache_lock);
|
||||
spin_lock(&vfsmount_lock);
|
||||
- prepend(&end, &buflen, "\0", 1);
|
||||
- if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
|
||||
- (prepend(&end, &buflen, " (deleted)", 10) != 0))
|
||||
+ if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
|
||||
+ if (flags & D_PATH_FAIL_DELETED) {
|
||||
+ buffer = ERR_PTR(-ENOENT);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (prepend(&buffer, &buflen, " (deleted)", 10) != 0)
|
||||
goto Elong;
|
||||
-
|
||||
+ }
|
||||
if (buflen < 1)
|
||||
goto Elong;
|
||||
- /* Get '/' right */
|
||||
- retval = end-1;
|
||||
- *retval = '/';
|
||||
|
||||
- for (;;) {
|
||||
+ while (dentry != root->dentry || vfsmnt != root->mnt) {
|
||||
struct dentry * parent;
|
||||
|
||||
- if (dentry == root->dentry && vfsmnt == root->mnt)
|
||||
- break;
|
||||
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
|
||||
- /* Global root? */
|
||||
if (vfsmnt->mnt_parent == vfsmnt) {
|
||||
goto global_root;
|
||||
}
|
||||
@@ -1945,27 +1947,51 @@ char *__d_path(const struct path *path,
|
||||
}
|
||||
parent = dentry->d_parent;
|
||||
prefetch(parent);
|
||||
- if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) ||
|
||||
- (prepend(&end, &buflen, "/", 1) != 0))
|
||||
+ if ((prepend_name(&buffer, &buflen, &dentry->d_name) != 0) ||
|
||||
+ (prepend(&buffer, &buflen, "/", 1) != 0))
|
||||
goto Elong;
|
||||
- retval = end;
|
||||
dentry = parent;
|
||||
}
|
||||
+ /* Get '/' right. */
|
||||
+ if (*buffer != '/' && prepend(&buffer, &buflen, "/", 1))
|
||||
+ goto Elong;
|
||||
|
||||
out:
|
||||
spin_unlock(&vfsmount_lock);
|
||||
- return retval;
|
||||
+ spin_unlock(&dcache_lock);
|
||||
+ return buffer;
|
||||
|
||||
global_root:
|
||||
- retval += 1; /* hit the slash */
|
||||
- if (prepend_name(&retval, &buflen, &dentry->d_name) != 0)
|
||||
+ /*
|
||||
+ * We went past the (vfsmount, dentry) we were looking for and have
|
||||
+ * either hit a root dentry, a lazily unmounted dentry, an
|
||||
+ * unconnected dentry, or the file is on a pseudo filesystem.
|
||||
+ */
|
||||
+ namelen = dentry->d_name.len;
|
||||
+ name = dentry->d_name.name;
|
||||
+
|
||||
+ /*
|
||||
+ * If this is a root dentry, then overwrite the slash. This
|
||||
+ * will also DTRT with pseudo filesystems which have root
|
||||
+ * dentries named "foo:".
|
||||
+ */
|
||||
+ if (IS_ROOT(dentry) && *buffer == '/') {
|
||||
+ buffer++;
|
||||
+ buflen++;
|
||||
+ }
|
||||
+ if ((flags & D_PATH_DISCONNECT) && *name == '/') {
|
||||
+ /* Make sure we won't return a pathname starting with '/' */
|
||||
+ name++;
|
||||
+ namelen--;
|
||||
+ }
|
||||
+ if (prepend(&buffer, &buflen, name, namelen))
|
||||
goto Elong;
|
||||
root->mnt = vfsmnt;
|
||||
root->dentry = dentry;
|
||||
goto out;
|
||||
|
||||
Elong:
|
||||
- retval = ERR_PTR(-ENAMETOOLONG);
|
||||
+ buffer = ERR_PTR(-ENAMETOOLONG);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2002,10 +2028,8 @@ char *d_path(const struct path *path, ch
|
||||
root = current->fs->root;
|
||||
path_get(&root);
|
||||
read_unlock(¤t->fs->lock);
|
||||
- spin_lock(&dcache_lock);
|
||||
tmp = root;
|
||||
- res = __d_path(path, &tmp, buf, buflen);
|
||||
- spin_unlock(&dcache_lock);
|
||||
+ res = __d_path(path, &tmp, buf, buflen, 0);
|
||||
path_put(&root);
|
||||
return res;
|
||||
}
|
||||
@@ -2088,9 +2112,9 @@ Elong:
|
||||
*/
|
||||
SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
|
||||
{
|
||||
- int error;
|
||||
- struct path pwd, root;
|
||||
- char *page = (char *) __get_free_page(GFP_USER);
|
||||
+ int error, len;
|
||||
+ struct path pwd, root, tmp;
|
||||
+ char *page = (char *) __get_free_page(GFP_USER), *cwd;
|
||||
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
@@ -2102,30 +2126,20 @@ SYSCALL_DEFINE2(getcwd, char __user *, b
|
||||
path_get(&root);
|
||||
read_unlock(¤t->fs->lock);
|
||||
|
||||
- error = -ENOENT;
|
||||
- /* Has the current directory has been unlinked? */
|
||||
- spin_lock(&dcache_lock);
|
||||
- if (IS_ROOT(pwd.dentry) || !d_unhashed(pwd.dentry)) {
|
||||
- unsigned long len;
|
||||
- struct path tmp = root;
|
||||
- char * cwd;
|
||||
-
|
||||
- cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE);
|
||||
- spin_unlock(&dcache_lock);
|
||||
-
|
||||
+ tmp = root;
|
||||
+ cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE, D_PATH_FAIL_DELETED);
|
||||
+ if (IS_ERR(cwd)) {
|
||||
error = PTR_ERR(cwd);
|
||||
- if (IS_ERR(cwd))
|
||||
- goto out;
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
- error = -ERANGE;
|
||||
- len = PAGE_SIZE + page - cwd;
|
||||
- if (len <= size) {
|
||||
- error = len;
|
||||
- if (copy_to_user(buf, cwd, len))
|
||||
- error = -EFAULT;
|
||||
- }
|
||||
- } else
|
||||
- spin_unlock(&dcache_lock);
|
||||
+ error = -ERANGE;
|
||||
+ len = PAGE_SIZE + page - cwd;
|
||||
+ if (len <= size) {
|
||||
+ error = len;
|
||||
+ if (copy_to_user(buf, cwd, len))
|
||||
+ error = -EFAULT;
|
||||
+ }
|
||||
|
||||
out:
|
||||
path_put(&pwd);
|
||||
Index: linux-2.6.27/fs/seq_file.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/fs/seq_file.c
|
||||
+++ linux-2.6.27/fs/seq_file.c
|
||||
@@ -441,9 +441,7 @@ int seq_path_root(struct seq_file *m, st
|
||||
char *s = m->buf + m->count;
|
||||
char *p;
|
||||
|
||||
- spin_lock(&dcache_lock);
|
||||
- p = __d_path(path, root, s, m->size - m->count);
|
||||
- spin_unlock(&dcache_lock);
|
||||
+ p = __d_path(path, root, s, m->size - m->count, 0);
|
||||
err = PTR_ERR(p);
|
||||
if (!IS_ERR(p)) {
|
||||
s = mangle_path(s, p, esc);
|
||||
Index: linux-2.6.27/include/linux/dcache.h
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/include/linux/dcache.h
|
||||
+++ linux-2.6.27/include/linux/dcache.h
|
||||
@@ -299,9 +299,12 @@ extern int d_validate(struct dentry *, s
|
||||
/*
|
||||
* helper function for dentry_operations.d_dname() members
|
||||
*/
|
||||
+#define D_PATH_FAIL_DELETED 1
|
||||
+#define D_PATH_DISCONNECT 2
|
||||
extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
|
||||
|
||||
-extern char *__d_path(const struct path *path, struct path *root, char *, int);
|
||||
+extern char *__d_path(const struct path *path, struct path *root, char *, int,
|
||||
+ int);
|
||||
extern char *d_path(const struct path *, char *, int);
|
||||
extern char *dentry_path(struct dentry *, char *, int);
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_getxattr()
|
||||
|
||||
The vfsmount will be passed down to the LSM hook so that LSMs can compute
|
||||
pathnames.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/nfsd/nfs4xdr.c | 2 +-
|
||||
fs/nfsd/vfs.c | 21 ++++++++++++---------
|
||||
fs/xattr.c | 15 ++++++++-------
|
||||
include/linux/nfsd/nfsd.h | 3 ++-
|
||||
include/linux/xattr.h | 2 +-
|
||||
5 files changed, 24 insertions(+), 19 deletions(-)
|
||||
|
||||
--- a/fs/nfsd/nfs4xdr.c
|
||||
+++ b/fs/nfsd/nfs4xdr.c
|
||||
@@ -1446,7 +1446,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
|
||||
}
|
||||
if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
|
||||
| FATTR4_WORD0_SUPPORTED_ATTRS)) {
|
||||
- err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
|
||||
+ err = nfsd4_get_nfs4_acl(rqstp, dentry, exp->ex_path.mnt, &acl);
|
||||
aclsupport = (err == 0);
|
||||
if (bmval0 & FATTR4_WORD0_ACL) {
|
||||
if (err == -EOPNOTSUPP)
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -420,11 +420,12 @@ out_nfserr:
|
||||
#if defined(CONFIG_NFSD_V2_ACL) || \
|
||||
defined(CONFIG_NFSD_V3_ACL) || \
|
||||
defined(CONFIG_NFSD_V4)
|
||||
-static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
|
||||
+static ssize_t nfsd_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ char *key, void **buf)
|
||||
{
|
||||
ssize_t buflen;
|
||||
|
||||
- buflen = vfs_getxattr(dentry, key, NULL, 0);
|
||||
+ buflen = vfs_getxattr(dentry, mnt, key, NULL, 0);
|
||||
if (buflen <= 0)
|
||||
return buflen;
|
||||
|
||||
@@ -432,7 +433,7 @@ static ssize_t nfsd_getxattr(struct dent
|
||||
if (!*buf)
|
||||
return -ENOMEM;
|
||||
|
||||
- return vfs_getxattr(dentry, key, *buf, buflen);
|
||||
+ return vfs_getxattr(dentry, mnt, key, *buf, buflen);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -513,13 +514,13 @@ out_nfserr:
|
||||
}
|
||||
|
||||
static struct posix_acl *
|
||||
-_get_posix_acl(struct dentry *dentry, char *key)
|
||||
+_get_posix_acl(struct dentry *dentry, struct vfsmount *mnt, char *key)
|
||||
{
|
||||
void *buf = NULL;
|
||||
struct posix_acl *pacl = NULL;
|
||||
int buflen;
|
||||
|
||||
- buflen = nfsd_getxattr(dentry, key, &buf);
|
||||
+ buflen = nfsd_getxattr(dentry, mnt, key, &buf);
|
||||
if (!buflen)
|
||||
buflen = -ENODATA;
|
||||
if (buflen <= 0)
|
||||
@@ -531,14 +532,15 @@ _get_posix_acl(struct dentry *dentry, ch
|
||||
}
|
||||
|
||||
int
|
||||
-nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl)
|
||||
+nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, struct nfs4_acl **acl)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error = 0;
|
||||
struct posix_acl *pacl = NULL, *dpacl = NULL;
|
||||
unsigned int flags = 0;
|
||||
|
||||
- pacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_ACCESS);
|
||||
+ pacl = _get_posix_acl(dentry, mnt, POSIX_ACL_XATTR_ACCESS);
|
||||
if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA)
|
||||
pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
|
||||
if (IS_ERR(pacl)) {
|
||||
@@ -548,7 +550,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqst
|
||||
}
|
||||
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
- dpacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_DEFAULT);
|
||||
+ dpacl = _get_posix_acl(dentry, mnt, POSIX_ACL_XATTR_DEFAULT);
|
||||
if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA)
|
||||
dpacl = NULL;
|
||||
else if (IS_ERR(dpacl)) {
|
||||
@@ -2080,7 +2082,8 @@ nfsd_get_posix_acl(struct svc_fh *fhp, i
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
- size = nfsd_getxattr(fhp->fh_dentry, name, &value);
|
||||
+ size = nfsd_getxattr(fhp->fh_dentry, fhp->fh_export->ex_path.mnt, name,
|
||||
+ &value);
|
||||
if (size < 0)
|
||||
return ERR_PTR(size);
|
||||
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -131,7 +131,8 @@ out_noalloc:
|
||||
EXPORT_SYMBOL_GPL(xattr_getsecurity);
|
||||
|
||||
ssize_t
|
||||
-vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
|
||||
+vfs_getxattr(struct dentry *dentry, struct vfsmount *mnt, const char *name,
|
||||
+ void *value, size_t size)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -314,8 +315,8 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, cons
|
||||
* Extended attribute GET operations
|
||||
*/
|
||||
static ssize_t
|
||||
-getxattr(struct dentry *d, const char __user *name, void __user *value,
|
||||
- size_t size)
|
||||
+getxattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name,
|
||||
+ void __user *value, size_t size)
|
||||
{
|
||||
ssize_t error;
|
||||
void *kvalue = NULL;
|
||||
@@ -335,7 +336,7 @@ getxattr(struct dentry *d, const char __
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
- error = vfs_getxattr(d, kname, kvalue, size);
|
||||
+ error = vfs_getxattr(dentry, mnt, kname, kvalue, size);
|
||||
if (error > 0) {
|
||||
if (size && copy_to_user(value, kvalue, error))
|
||||
error = -EFAULT;
|
||||
@@ -357,7 +358,7 @@ SYSCALL_DEFINE4(getxattr, const char __u
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = getxattr(path.dentry, name, value, size);
|
||||
+ error = getxattr(path.dentry, path.mnt, name, value, size);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -371,7 +372,7 @@ SYSCALL_DEFINE4(lgetxattr, const char __
|
||||
error = user_lpath(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = getxattr(path.dentry, name, value, size);
|
||||
+ error = getxattr(path.dentry, path.mnt, name, value, size);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -386,7 +387,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, cons
|
||||
if (!f)
|
||||
return error;
|
||||
audit_inode(NULL, f->f_path.dentry);
|
||||
- error = getxattr(f->f_path.dentry, name, value, size);
|
||||
+ error = getxattr(f->f_path.dentry, f->f_path.mnt, name, value, size);
|
||||
fput(f);
|
||||
return error;
|
||||
}
|
||||
--- a/include/linux/nfsd/nfsd.h
|
||||
+++ b/include/linux/nfsd/nfsd.h
|
||||
@@ -85,7 +85,8 @@ __be32 nfsd_setattr(struct svc_rqst *,
|
||||
#ifdef CONFIG_NFSD_V4
|
||||
__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
|
||||
struct nfs4_acl *);
|
||||
-int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
|
||||
+int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *,
|
||||
+ struct vfsmount *mnt, struct nfs4_acl **);
|
||||
#endif /* CONFIG_NFSD_V4 */
|
||||
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
|
||||
char *name, int len, struct iattr *attrs,
|
||||
--- a/include/linux/xattr.h
|
||||
+++ b/include/linux/xattr.h
|
||||
@@ -48,7 +48,7 @@ struct xattr_handler {
|
||||
};
|
||||
|
||||
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
|
||||
-ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
|
||||
+ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, const char *, void *, size_t);
|
||||
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
|
||||
int vfs_setxattr(struct dentry *, struct vfsmount *, const char *, const void *, size_t, int);
|
||||
int vfs_removexattr(struct dentry *, const char *);
|
||||
@@ -1,91 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add struct vfsmount parameters to vfs_link()
|
||||
|
||||
The vfsmount will be passed down to the LSM hook so that LSMs can compute
|
||||
pathnames.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/ecryptfs/inode.c | 9 +++++++--
|
||||
fs/namei.c | 6 ++++--
|
||||
fs/nfsd/vfs.c | 3 ++-
|
||||
include/linux/fs.h | 2 +-
|
||||
4 files changed, 14 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -403,19 +403,24 @@ static int ecryptfs_link(struct dentry *
|
||||
struct dentry *new_dentry)
|
||||
{
|
||||
struct dentry *lower_old_dentry;
|
||||
+ struct vfsmount *lower_old_mnt;
|
||||
struct dentry *lower_new_dentry;
|
||||
+ struct vfsmount *lower_new_mnt;
|
||||
struct dentry *lower_dir_dentry;
|
||||
u64 file_size_save;
|
||||
int rc;
|
||||
|
||||
file_size_save = i_size_read(old_dentry->d_inode);
|
||||
lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
|
||||
+ lower_old_mnt = ecryptfs_dentry_to_lower_mnt(old_dentry);
|
||||
lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
|
||||
+ lower_new_mnt = ecryptfs_dentry_to_lower_mnt(new_dentry);
|
||||
dget(lower_old_dentry);
|
||||
dget(lower_new_dentry);
|
||||
lower_dir_dentry = lock_parent(lower_new_dentry);
|
||||
- rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
|
||||
- lower_new_dentry);
|
||||
+ rc = vfs_link(lower_old_dentry, lower_old_mnt,
|
||||
+ lower_dir_dentry->d_inode, lower_new_dentry,
|
||||
+ lower_new_mnt);
|
||||
if (rc || !lower_new_dentry->d_inode)
|
||||
goto out_lock;
|
||||
rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2412,7 +2412,7 @@ SYSCALL_DEFINE2(symlink, const char __us
|
||||
return sys_symlinkat(oldname, AT_FDCWD, newname);
|
||||
}
|
||||
|
||||
-int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
|
||||
+int vfs_link(struct dentry *old_dentry, struct vfsmount *old_mnt, struct inode *dir, struct dentry *new_dentry, struct vfsmount *new_mnt)
|
||||
{
|
||||
struct inode *inode = old_dentry->d_inode;
|
||||
int error;
|
||||
@@ -2490,7 +2490,9 @@ SYSCALL_DEFINE5(linkat, int, olddfd, con
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
- error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
|
||||
+ error = vfs_link(old_path.dentry, old_path.mnt,
|
||||
+ nd.path.dentry->d_inode,
|
||||
+ new_dentry, nd.path.mnt);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
out_dput:
|
||||
dput(new_dentry);
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1650,7 +1650,8 @@ nfsd_link(struct svc_rqst *rqstp, struct
|
||||
err = nfserrno(host_err);
|
||||
goto out_dput;
|
||||
}
|
||||
- host_err = vfs_link(dold, dirp, dnew);
|
||||
+ host_err = vfs_link(dold, tfhp->fh_export->ex_path.mnt, dirp,
|
||||
+ dnew, ffhp->fh_export->ex_path.mnt);
|
||||
if (!host_err) {
|
||||
if (EX_ISSYNC(ffhp->fh_export)) {
|
||||
err = nfserrno(nfsd_sync_dir(ddir));
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1181,7 +1181,7 @@ extern int vfs_create(struct inode *, st
|
||||
extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int);
|
||||
extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t);
|
||||
extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *);
|
||||
-extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
|
||||
+extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
|
||||
extern int vfs_rmdir(struct inode *, struct dentry *);
|
||||
extern int vfs_unlink(struct inode *, struct dentry *);
|
||||
extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
|
||||
@@ -1,101 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_listxattr()
|
||||
|
||||
The vfsmount will be passed down to the LSM hook so that LSMs can compute
|
||||
pathnames.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/xattr.c | 25 ++++++++++++++-----------
|
||||
include/linux/xattr.h | 2 +-
|
||||
2 files changed, 15 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -168,18 +168,20 @@ nolsm:
|
||||
EXPORT_SYMBOL_GPL(vfs_getxattr);
|
||||
|
||||
ssize_t
|
||||
-vfs_listxattr(struct dentry *d, char *list, size_t size)
|
||||
+vfs_listxattr(struct dentry *dentry, struct vfsmount *mnt, char *list,
|
||||
+ size_t size)
|
||||
{
|
||||
+ struct inode *inode = dentry->d_inode;
|
||||
ssize_t error;
|
||||
|
||||
- error = security_inode_listxattr(d);
|
||||
+ error = security_inode_listxattr(dentry);
|
||||
if (error)
|
||||
return error;
|
||||
error = -EOPNOTSUPP;
|
||||
- if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
|
||||
- error = d->d_inode->i_op->listxattr(d, list, size);
|
||||
- } else {
|
||||
- error = security_inode_listsecurity(d->d_inode, list, size);
|
||||
+ if (inode->i_op && inode->i_op->listxattr)
|
||||
+ error = inode->i_op->listxattr(dentry, list, size);
|
||||
+ else {
|
||||
+ error = security_inode_listsecurity(inode, list, size);
|
||||
if (size && error > size)
|
||||
error = -ERANGE;
|
||||
}
|
||||
@@ -396,7 +398,8 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, cons
|
||||
* Extended attribute LIST operations
|
||||
*/
|
||||
static ssize_t
|
||||
-listxattr(struct dentry *d, char __user *list, size_t size)
|
||||
+listxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *list,
|
||||
+ size_t size)
|
||||
{
|
||||
ssize_t error;
|
||||
char *klist = NULL;
|
||||
@@ -409,7 +412,7 @@ listxattr(struct dentry *d, char __user
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
- error = vfs_listxattr(d, klist, size);
|
||||
+ error = vfs_listxattr(dentry, mnt, klist, size);
|
||||
if (error > 0) {
|
||||
if (size && copy_to_user(list, klist, error))
|
||||
error = -EFAULT;
|
||||
@@ -431,7 +434,7 @@ SYSCALL_DEFINE3(listxattr, const char __
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = listxattr(path.dentry, list, size);
|
||||
+ error = listxattr(path.dentry, path.mnt, list, size);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -445,7 +448,7 @@ SYSCALL_DEFINE3(llistxattr, const char _
|
||||
error = user_lpath(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = listxattr(path.dentry, list, size);
|
||||
+ error = listxattr(path.dentry, path.mnt, list, size);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -459,7 +462,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, cha
|
||||
if (!f)
|
||||
return error;
|
||||
audit_inode(NULL, f->f_path.dentry);
|
||||
- error = listxattr(f->f_path.dentry, list, size);
|
||||
+ error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size);
|
||||
fput(f);
|
||||
return error;
|
||||
}
|
||||
--- a/include/linux/xattr.h
|
||||
+++ b/include/linux/xattr.h
|
||||
@@ -49,7 +49,7 @@ struct xattr_handler {
|
||||
|
||||
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
|
||||
ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, const char *, void *, size_t);
|
||||
-ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
|
||||
+ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list, size_t size);
|
||||
int vfs_setxattr(struct dentry *, struct vfsmount *, const char *, const void *, size_t, int);
|
||||
int vfs_removexattr(struct dentry *, const char *);
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add struct vfsmount parameter to vfs_mkdir()
|
||||
|
||||
The vfsmount will be passed down to the LSM hook so that LSMs can compute
|
||||
pathnames.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/ecryptfs/inode.c | 5 ++++-
|
||||
fs/namei.c | 5 +++--
|
||||
fs/nfsd/nfs4recover.c | 3 ++-
|
||||
fs/nfsd/vfs.c | 8 +++++---
|
||||
include/linux/fs.h | 2 +-
|
||||
kernel/cgroup.c | 2 +-
|
||||
6 files changed, 16 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -501,11 +501,14 @@ static int ecryptfs_mkdir(struct inode *
|
||||
{
|
||||
int rc;
|
||||
struct dentry *lower_dentry;
|
||||
+ struct vfsmount *lower_mnt;
|
||||
struct dentry *lower_dir_dentry;
|
||||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
- rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode);
|
||||
+ rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, lower_mnt,
|
||||
+ mode);
|
||||
if (rc || !lower_dentry->d_inode)
|
||||
goto out;
|
||||
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2077,7 +2077,8 @@ SYSCALL_DEFINE3(mknod, const char __user
|
||||
return sys_mknodat(AT_FDCWD, filename, mode, dev);
|
||||
}
|
||||
|
||||
-int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
+int vfs_mkdir(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ int mode)
|
||||
{
|
||||
int error = may_create(dir, dentry, 1);
|
||||
|
||||
@@ -2120,7 +2121,7 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
- error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
|
||||
+ error = vfs_mkdir(nd.path.dentry->d_inode, dentry, nd.path.mnt, mode);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
out_dput:
|
||||
dput(dentry);
|
||||
--- a/fs/nfsd/nfs4recover.c
|
||||
+++ b/fs/nfsd/nfs4recover.c
|
||||
@@ -158,7 +158,8 @@ nfsd4_create_clid_dir(struct nfs4_client
|
||||
status = mnt_want_write(rec_dir.path.mnt);
|
||||
if (status)
|
||||
goto out_put;
|
||||
- status = vfs_mkdir(rec_dir.path.dentry->d_inode, dentry, S_IRWXU);
|
||||
+ status = vfs_mkdir(rec_dir.path.dentry->d_inode, dentry,
|
||||
+ rec_dir.path.mnt, S_IRWXU);
|
||||
mnt_drop_write(rec_dir.path.mnt);
|
||||
out_put:
|
||||
dput(dentry);
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1215,6 +1215,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
|
||||
int type, dev_t rdev, struct svc_fh *resfhp)
|
||||
{
|
||||
struct dentry *dentry, *dchild = NULL;
|
||||
+ struct svc_export *exp;
|
||||
struct inode *dirp;
|
||||
__be32 err;
|
||||
__be32 err2;
|
||||
@@ -1232,6 +1233,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
|
||||
goto out;
|
||||
|
||||
dentry = fhp->fh_dentry;
|
||||
+ exp = fhp->fh_export;
|
||||
dirp = dentry->d_inode;
|
||||
|
||||
err = nfserr_notdir;
|
||||
@@ -1248,7 +1250,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
|
||||
host_err = PTR_ERR(dchild);
|
||||
if (IS_ERR(dchild))
|
||||
goto out_nfserr;
|
||||
- err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
|
||||
+ err = fh_compose(resfhp, exp, dchild, fhp);
|
||||
if (err)
|
||||
goto out;
|
||||
} else {
|
||||
@@ -1298,7 +1300,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
|
||||
host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
|
||||
break;
|
||||
case S_IFDIR:
|
||||
- host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
|
||||
+ host_err = vfs_mkdir(dirp, dchild, exp->ex_path.mnt, iap->ia_mode);
|
||||
break;
|
||||
case S_IFCHR:
|
||||
case S_IFBLK:
|
||||
@@ -1312,7 +1314,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
|
||||
goto out_nfserr;
|
||||
}
|
||||
|
||||
- if (EX_ISSYNC(fhp->fh_export)) {
|
||||
+ if (EX_ISSYNC(exp)) {
|
||||
err = nfserrno(nfsd_sync_dir(dentry));
|
||||
write_inode_now(dchild->d_inode, 1);
|
||||
}
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1178,7 +1178,7 @@ extern void unlock_super(struct super_bl
|
||||
*/
|
||||
extern int vfs_permission(struct nameidata *, int);
|
||||
extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
|
||||
-extern int vfs_mkdir(struct inode *, struct dentry *, int);
|
||||
+extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int);
|
||||
extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
|
||||
extern int vfs_symlink(struct inode *, struct dentry *, const char *);
|
||||
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
|
||||
--- a/kernel/cgroup.c
|
||||
+++ b/kernel/cgroup.c
|
||||
@@ -2911,7 +2911,7 @@ int cgroup_clone(struct task_struct *tsk
|
||||
}
|
||||
|
||||
/* Create the cgroup directory, which also creates the cgroup */
|
||||
- ret = vfs_mkdir(inode, dentry, S_IFDIR | 0755);
|
||||
+ ret = vfs_mkdir(inode, dentry, NULL, S_IFDIR | 0755);
|
||||
child = __d_cgrp(dentry);
|
||||
dput(dentry);
|
||||
if (ret) {
|
||||
@@ -1,99 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_mknod()
|
||||
|
||||
The vfsmount will be passed down to the LSM hook so that LSMs can compute
|
||||
pathnames.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/ecryptfs/inode.c | 5 ++++-
|
||||
fs/namei.c | 10 ++++++----
|
||||
fs/nfsd/vfs.c | 3 ++-
|
||||
include/linux/fs.h | 2 +-
|
||||
net/unix/af_unix.c | 3 ++-
|
||||
5 files changed, 15 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -552,11 +552,14 @@ ecryptfs_mknod(struct inode *dir, struct
|
||||
{
|
||||
int rc;
|
||||
struct dentry *lower_dentry;
|
||||
+ struct vfsmount *lower_mnt;
|
||||
struct dentry *lower_dir_dentry;
|
||||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
- rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev);
|
||||
+ rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, lower_mnt, mode,
|
||||
+ dev);
|
||||
if (rc || !lower_dentry->d_inode)
|
||||
goto out;
|
||||
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -1976,7 +1976,8 @@ fail:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lookup_create);
|
||||
|
||||
-int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
|
||||
+int vfs_mknod(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ int mode, dev_t dev)
|
||||
{
|
||||
int error = may_create(dir, dentry, 0);
|
||||
|
||||
@@ -2054,11 +2055,12 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const
|
||||
error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
|
||||
break;
|
||||
case S_IFCHR: case S_IFBLK:
|
||||
- error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,
|
||||
- new_decode_dev(dev));
|
||||
+ error = vfs_mknod(nd.path.dentry->d_inode, dentry,
|
||||
+ nd.path, mode, new_decode_dev(dev));
|
||||
break;
|
||||
case S_IFIFO: case S_IFSOCK:
|
||||
- error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
|
||||
+ error = vfs_mknod(nd.path.dentry->d_inode, dentry,
|
||||
+ nd.path, mode, 0);
|
||||
break;
|
||||
}
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1306,7 +1306,8 @@ nfsd_create(struct svc_rqst *rqstp, stru
|
||||
case S_IFBLK:
|
||||
case S_IFIFO:
|
||||
case S_IFSOCK:
|
||||
- host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
|
||||
+ host_err = vfs_mknod(dirp, dchild, exp->ex_path.mnt,
|
||||
+ iap->ia_mode, rdev);
|
||||
break;
|
||||
}
|
||||
if (host_err < 0) {
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1179,7 +1179,7 @@ extern void unlock_super(struct super_bl
|
||||
extern int vfs_permission(struct nameidata *, int);
|
||||
extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
|
||||
extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int);
|
||||
-extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
|
||||
+extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t);
|
||||
extern int vfs_symlink(struct inode *, struct dentry *, const char *);
|
||||
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
|
||||
extern int vfs_rmdir(struct inode *, struct dentry *);
|
||||
--- a/net/unix/af_unix.c
|
||||
+++ b/net/unix/af_unix.c
|
||||
@@ -827,7 +827,8 @@ static int unix_bind(struct socket *sock
|
||||
err = mnt_want_write(nd.path.mnt);
|
||||
if (err)
|
||||
goto out_mknod_dput;
|
||||
- err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0);
|
||||
+ err = vfs_mknod(nd.path.dentry->d_inode, dentry, nd.path.mnt,
|
||||
+ mode, 0);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
if (err)
|
||||
goto out_mknod_dput;
|
||||
@@ -1,291 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a vfsmount parameter to notify_change()
|
||||
|
||||
The vfsmount parameter must be set appropriately for files visibile
|
||||
outside the kernel. Files that are only used in a filesystem (e.g.,
|
||||
reiserfs xattr files) will have a NULL vfsmount.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/attr.c | 3 ++-
|
||||
fs/ecryptfs/inode.c | 4 +++-
|
||||
fs/exec.c | 3 ++-
|
||||
fs/hpfs/namei.c | 2 +-
|
||||
fs/namei.c | 2 +-
|
||||
fs/nfsd/vfs.c | 8 ++++----
|
||||
fs/open.c | 28 +++++++++++++++-------------
|
||||
fs/utimes.c | 2 +-
|
||||
include/linux/fs.h | 6 +++---
|
||||
mm/filemap.c | 2 +-
|
||||
10 files changed, 33 insertions(+), 27 deletions(-)
|
||||
|
||||
--- a/fs/attr.c
|
||||
+++ b/fs/attr.c
|
||||
@@ -100,7 +100,8 @@ int inode_setattr(struct inode * inode,
|
||||
}
|
||||
EXPORT_SYMBOL(inode_setattr);
|
||||
|
||||
-int notify_change(struct dentry * dentry, struct iattr * attr)
|
||||
+int notify_change(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
mode_t mode = inode->i_mode;
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -850,6 +850,7 @@ static int ecryptfs_setattr(struct dentr
|
||||
{
|
||||
int rc = 0;
|
||||
struct dentry *lower_dentry;
|
||||
+ struct vfsmount *lower_mnt;
|
||||
struct inode *inode;
|
||||
struct inode *lower_inode;
|
||||
struct ecryptfs_crypt_stat *crypt_stat;
|
||||
@@ -860,6 +861,7 @@ static int ecryptfs_setattr(struct dentr
|
||||
inode = dentry->d_inode;
|
||||
lower_inode = ecryptfs_inode_to_lower(inode);
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
mutex_lock(&crypt_stat->cs_mutex);
|
||||
if (S_ISDIR(dentry->d_inode->i_mode))
|
||||
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
|
||||
@@ -911,7 +913,7 @@ static int ecryptfs_setattr(struct dentr
|
||||
ia->ia_valid &= ~ATTR_MODE;
|
||||
|
||||
mutex_lock(&lower_dentry->d_inode->i_mutex);
|
||||
- rc = notify_change(lower_dentry, ia);
|
||||
+ rc = notify_change(lower_dentry, lower_mnt, ia);
|
||||
mutex_unlock(&lower_dentry->d_inode->i_mutex);
|
||||
out:
|
||||
fsstack_copy_attr_all(inode, lower_inode, NULL);
|
||||
--- a/fs/exec.c
|
||||
+++ b/fs/exec.c
|
||||
@@ -1841,7 +1841,8 @@ int do_coredump(long signr, int exit_cod
|
||||
goto close_fail;
|
||||
if (!file->f_op->write)
|
||||
goto close_fail;
|
||||
- if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0)
|
||||
+ if (!ispipe &&
|
||||
+ do_truncate(file->f_path.dentry, file->f_path.mnt, 0, 0, file) != 0)
|
||||
goto close_fail;
|
||||
|
||||
retval = binfmt->core_dump(signr, regs, file, core_limit);
|
||||
--- a/fs/hpfs/namei.c
|
||||
+++ b/fs/hpfs/namei.c
|
||||
@@ -426,7 +426,7 @@ again:
|
||||
/*printk("HPFS: truncating file before delete.\n");*/
|
||||
newattrs.ia_size = 0;
|
||||
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
|
||||
- err = notify_change(dentry, &newattrs);
|
||||
+ err = notify_change(dentry, NULL, &newattrs);
|
||||
put_write_access(inode);
|
||||
if (!err)
|
||||
goto again;
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -1619,7 +1619,7 @@ int may_open(struct nameidata *nd, int a
|
||||
if (!error) {
|
||||
DQUOT_INIT(inode);
|
||||
|
||||
- error = do_truncate(dentry, 0,
|
||||
+ error = do_truncate(dentry, nd->path.mnt, 0,
|
||||
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
|
||||
NULL);
|
||||
}
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -397,7 +397,7 @@ nfsd_setattr(struct svc_rqst *rqstp, str
|
||||
err = nfserr_notsync;
|
||||
if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
|
||||
fh_lock(fhp);
|
||||
- host_err = notify_change(dentry, iap);
|
||||
+ host_err = notify_change(dentry, fhp->fh_export->ex_path.mnt, iap);
|
||||
/* to get NFSERR_JUKEBOX on the wire, need -ETIMEDOUT */
|
||||
if (host_err == -EAGAIN)
|
||||
host_err = -ETIMEDOUT;
|
||||
@@ -964,13 +964,13 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
-static void kill_suid(struct dentry *dentry)
|
||||
+static void kill_suid(struct dentry *dentry, struct vfsmount *mnt)
|
||||
{
|
||||
struct iattr ia;
|
||||
ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
|
||||
|
||||
mutex_lock(&dentry->d_inode->i_mutex);
|
||||
- notify_change(dentry, &ia);
|
||||
+ notify_change(dentry, mnt, &ia);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
}
|
||||
|
||||
@@ -1033,7 +1033,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s
|
||||
|
||||
/* clear setuid/setgid flag after write */
|
||||
if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID)))
|
||||
- kill_suid(dentry);
|
||||
+ kill_suid(dentry, exp->ex_path.mnt);
|
||||
|
||||
if (host_err >= 0 && stable) {
|
||||
static ino_t last_ino;
|
||||
--- a/fs/open.c
|
||||
+++ b/fs/open.c
|
||||
@@ -195,8 +195,8 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
-int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
|
||||
- struct file *filp)
|
||||
+int do_truncate(struct dentry *dentry, struct vfsmount *mnt, loff_t length,
|
||||
+ unsigned int time_attrs, struct file *filp)
|
||||
{
|
||||
int err;
|
||||
struct iattr newattrs;
|
||||
@@ -216,7 +216,7 @@ int do_truncate(struct dentry *dentry, l
|
||||
newattrs.ia_valid |= should_remove_suid(dentry);
|
||||
|
||||
mutex_lock(&dentry->d_inode->i_mutex);
|
||||
- err = notify_change(dentry, &newattrs);
|
||||
+ err = notify_change(dentry, mnt, &newattrs);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
return err;
|
||||
}
|
||||
@@ -272,7 +272,7 @@ static long do_sys_truncate(const char _
|
||||
error = locks_verify_truncate(inode, NULL, length);
|
||||
if (!error) {
|
||||
DQUOT_INIT(inode);
|
||||
- error = do_truncate(path.dentry, length, 0, NULL);
|
||||
+ error = do_truncate(path.dentry, path.mnt, length, 0, NULL);
|
||||
}
|
||||
|
||||
put_write_and_out:
|
||||
@@ -327,7 +327,8 @@ static long do_sys_ftruncate(unsigned in
|
||||
|
||||
error = locks_verify_truncate(inode, file, length);
|
||||
if (!error)
|
||||
- error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
|
||||
+ error = do_truncate(dentry, file->f_path.mnt, length,
|
||||
+ ATTR_MTIME|ATTR_CTIME, file);
|
||||
out_putf:
|
||||
fput(file);
|
||||
out:
|
||||
@@ -624,7 +625,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd
|
||||
mode = inode->i_mode;
|
||||
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
|
||||
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||
- err = notify_change(dentry, &newattrs);
|
||||
+ err = notify_change(dentry, file->f_path.mnt, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
mnt_drop_write(file->f_path.mnt);
|
||||
out_putf:
|
||||
@@ -653,7 +654,7 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, cons
|
||||
mode = inode->i_mode;
|
||||
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
|
||||
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||
- error = notify_change(path.dentry, &newattrs);
|
||||
+ error = notify_change(path.dentry, path.mnt, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
mnt_drop_write(path.mnt);
|
||||
dput_and_out:
|
||||
@@ -667,7 +668,8 @@ SYSCALL_DEFINE2(chmod, const char __user
|
||||
return sys_fchmodat(AT_FDCWD, filename, mode);
|
||||
}
|
||||
|
||||
-static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
|
||||
+static int chown_common(struct dentry * dentry, struct vfsmount *mnt,
|
||||
+ uid_t user, gid_t group)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -686,7 +688,7 @@ static int chown_common(struct dentry *
|
||||
newattrs.ia_valid |=
|
||||
ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
|
||||
mutex_lock(&inode->i_mutex);
|
||||
- error = notify_change(dentry, &newattrs);
|
||||
+ error = notify_change(dentry, mnt, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
return error;
|
||||
@@ -703,7 +705,7 @@ SYSCALL_DEFINE3(chown, const char __user
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
- error = chown_common(path.dentry, user, group);
|
||||
+ error = chown_common(path.dentry, path.mnt, user, group);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
@@ -728,7 +730,7 @@ SYSCALL_DEFINE5(fchownat, int, dfd, cons
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
- error = chown_common(path.dentry, user, group);
|
||||
+ error = chown_common(path.dentry, path.mnt, user, group);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
@@ -747,7 +749,7 @@ SYSCALL_DEFINE3(lchown, const char __use
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
- error = chown_common(path.dentry, user, group);
|
||||
+ error = chown_common(path.dentry, path.mnt, user, group);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
@@ -770,7 +772,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd
|
||||
goto out_fput;
|
||||
dentry = file->f_path.dentry;
|
||||
audit_inode(NULL, dentry);
|
||||
- error = chown_common(dentry, user, group);
|
||||
+ error = chown_common(dentry, file->f_path.mnt, user, group);
|
||||
mnt_drop_write(file->f_path.mnt);
|
||||
out_fput:
|
||||
fput(file);
|
||||
--- a/fs/utimes.c
|
||||
+++ b/fs/utimes.c
|
||||
@@ -102,7 +102,7 @@ static int utimes_common(struct path *pa
|
||||
}
|
||||
}
|
||||
mutex_lock(&inode->i_mutex);
|
||||
- error = notify_change(path->dentry, &newattrs);
|
||||
+ error = notify_change(path->dentry, path->mnt, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
mnt_drop_write_and_out:
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1636,8 +1636,8 @@ static inline int break_lease(struct ino
|
||||
|
||||
/* fs/open.c */
|
||||
|
||||
-extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
|
||||
- struct file *filp);
|
||||
+extern int do_truncate(struct dentry *, struct vfsmount *, loff_t start,
|
||||
+ unsigned int time_attrs, struct file *filp);
|
||||
extern long do_sys_open(int dfd, const char __user *filename, int flags,
|
||||
int mode);
|
||||
extern struct file *filp_open(const char *, int, int);
|
||||
@@ -1798,7 +1798,7 @@ extern int do_remount_sb(struct super_bl
|
||||
#ifdef CONFIG_BLOCK
|
||||
extern sector_t bmap(struct inode *, sector_t);
|
||||
#endif
|
||||
-extern int notify_change(struct dentry *, struct iattr *);
|
||||
+extern int notify_change(struct dentry *, struct vfsmount *, struct iattr *);
|
||||
extern int inode_permission(struct inode *, int);
|
||||
extern int generic_permission(struct inode *, int,
|
||||
int (*check_acl)(struct inode *, int));
|
||||
--- a/mm/filemap.c
|
||||
+++ b/mm/filemap.c
|
||||
@@ -1831,7 +1831,7 @@ static int __remove_suid(struct path *pa
|
||||
struct iattr newattrs;
|
||||
|
||||
newattrs.ia_valid = ATTR_FORCE | kill;
|
||||
- return notify_change(path->dentry, &newattrs);
|
||||
+ return notify_change(path->dentry, path->mnt, &newattrs);
|
||||
}
|
||||
|
||||
int file_remove_suid(struct file *file)
|
||||
@@ -1,127 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_removexattr()
|
||||
|
||||
The vfsmount will be passed down to the LSM hook so that LSMs can compute
|
||||
pathnames.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/nfsd/vfs.c | 11 ++++++-----
|
||||
fs/xattr.c | 12 ++++++------
|
||||
include/linux/xattr.h | 2 +-
|
||||
3 files changed, 13 insertions(+), 12 deletions(-)
|
||||
|
||||
Index: linux-2.6.27/fs/nfsd/vfs.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/fs/nfsd/vfs.c
|
||||
+++ linux-2.6.27/fs/nfsd/vfs.c
|
||||
@@ -2095,6 +2095,7 @@ nfsd_get_posix_acl(struct svc_fh *fhp, i
|
||||
int
|
||||
nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
|
||||
{
|
||||
+ struct vfsmount *mnt;
|
||||
struct inode *inode = fhp->fh_dentry->d_inode;
|
||||
char *name;
|
||||
void *value = NULL;
|
||||
@@ -2127,22 +2128,22 @@ nfsd_set_posix_acl(struct svc_fh *fhp, i
|
||||
} else
|
||||
size = 0;
|
||||
|
||||
- error = mnt_want_write(fhp->fh_export->ex_path.mnt);
|
||||
+ mnt = fhp->fh_export->ex_path.mnt;
|
||||
+ error = mnt_want_write(mnt);
|
||||
if (error)
|
||||
goto getout;
|
||||
if (size)
|
||||
- error = vfs_setxattr(fhp->fh_dentry, fhp->fh_export->ex_path.mnt,
|
||||
- name, value, size,0);
|
||||
+ error = vfs_setxattr(fhp->fh_dentry, mnt, name, value, size,0);
|
||||
else {
|
||||
if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
|
||||
error = 0;
|
||||
else {
|
||||
- error = vfs_removexattr(fhp->fh_dentry, name);
|
||||
+ error = vfs_removexattr(fhp->fh_dentry, mnt, name);
|
||||
if (error == -ENODATA)
|
||||
error = 0;
|
||||
}
|
||||
}
|
||||
- mnt_drop_write(fhp->fh_export->ex_path.mnt);
|
||||
+ mnt_drop_write(mnt);
|
||||
|
||||
getout:
|
||||
kfree(value);
|
||||
Index: linux-2.6.27/fs/xattr.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/fs/xattr.c
|
||||
+++ linux-2.6.27/fs/xattr.c
|
||||
@@ -190,7 +190,7 @@ vfs_listxattr(struct dentry *dentry, str
|
||||
EXPORT_SYMBOL_GPL(vfs_listxattr);
|
||||
|
||||
int
|
||||
-vfs_removexattr(struct dentry *dentry, const char *name)
|
||||
+vfs_removexattr(struct dentry *dentry, struct vfsmount *mnt, const char *name)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -471,7 +471,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, cha
|
||||
* Extended attribute REMOVE operations
|
||||
*/
|
||||
static long
|
||||
-removexattr(struct dentry *d, const char __user *name)
|
||||
+removexattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name)
|
||||
{
|
||||
int error;
|
||||
char kname[XATTR_NAME_MAX + 1];
|
||||
@@ -482,7 +482,7 @@ removexattr(struct dentry *d, const char
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
- return vfs_removexattr(d, kname);
|
||||
+ return vfs_removexattr(dentry, mnt, kname);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
|
||||
@@ -496,7 +496,7 @@ SYSCALL_DEFINE2(removexattr, const char
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = removexattr(path.dentry, name);
|
||||
+ error = removexattr(path.dentry, path.mnt, name);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -514,7 +514,7 @@ SYSCALL_DEFINE2(lremovexattr, const char
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = removexattr(path.dentry, name);
|
||||
+ error = removexattr(path.dentry, path.mnt, name);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -534,7 +534,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, c
|
||||
audit_inode(NULL, dentry);
|
||||
error = mnt_want_write_file(f->f_path.mnt, f);
|
||||
if (!error) {
|
||||
- error = removexattr(dentry, name);
|
||||
+ error = removexattr(dentry, f->f_path.mnt, name);
|
||||
mnt_drop_write(f->f_path.mnt);
|
||||
}
|
||||
fput(f);
|
||||
Index: linux-2.6.27/include/linux/xattr.h
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/include/linux/xattr.h
|
||||
+++ linux-2.6.27/include/linux/xattr.h
|
||||
@@ -51,7 +51,7 @@ ssize_t xattr_getsecurity(struct inode *
|
||||
ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, const char *, void *, size_t);
|
||||
ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list, size_t size);
|
||||
int vfs_setxattr(struct dentry *, struct vfsmount *, const char *, const void *, size_t, int);
|
||||
-int vfs_removexattr(struct dentry *, const char *);
|
||||
+int vfs_removexattr(struct dentry *, struct vfsmount *mnt, const char *);
|
||||
|
||||
ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size);
|
||||
ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
|
||||
@@ -1,125 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add struct vfsmount parameters to vfs_rename()
|
||||
|
||||
The vfsmount will be passed down to the LSM hook so that LSMs can compute
|
||||
pathnames.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/ecryptfs/inode.c | 7 ++++++-
|
||||
fs/namei.c | 19 ++++++++++++-------
|
||||
fs/nfsd/vfs.c | 3 ++-
|
||||
include/linux/fs.h | 2 +-
|
||||
4 files changed, 21 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -590,19 +590,24 @@ ecryptfs_rename(struct inode *old_dir, s
|
||||
{
|
||||
int rc;
|
||||
struct dentry *lower_old_dentry;
|
||||
+ struct vfsmount *lower_old_mnt;
|
||||
struct dentry *lower_new_dentry;
|
||||
+ struct vfsmount *lower_new_mnt;
|
||||
struct dentry *lower_old_dir_dentry;
|
||||
struct dentry *lower_new_dir_dentry;
|
||||
|
||||
lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
|
||||
+ lower_old_mnt = ecryptfs_dentry_to_lower_mnt(old_dentry);
|
||||
lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
|
||||
+ lower_new_mnt = ecryptfs_dentry_to_lower_mnt(new_dentry);
|
||||
dget(lower_old_dentry);
|
||||
dget(lower_new_dentry);
|
||||
lower_old_dir_dentry = dget_parent(lower_old_dentry);
|
||||
lower_new_dir_dentry = dget_parent(lower_new_dentry);
|
||||
lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
|
||||
rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
|
||||
- lower_new_dir_dentry->d_inode, lower_new_dentry);
|
||||
+ lower_old_mnt, lower_new_dir_dentry->d_inode,
|
||||
+ lower_new_dentry, lower_new_mnt);
|
||||
if (rc)
|
||||
goto out_lock;
|
||||
fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode, NULL);
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2547,7 +2547,8 @@ SYSCALL_DEFINE2(link, const char __user
|
||||
* locking].
|
||||
*/
|
||||
static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
|
||||
- struct inode *new_dir, struct dentry *new_dentry)
|
||||
+ struct vfsmount *old_mnt, struct inode *new_dir,
|
||||
+ struct dentry *new_dentry, struct vfsmount *new_mnt)
|
||||
{
|
||||
int error = 0;
|
||||
struct inode *target;
|
||||
@@ -2590,7 +2591,8 @@ static int vfs_rename_dir(struct inode *
|
||||
}
|
||||
|
||||
static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
|
||||
- struct inode *new_dir, struct dentry *new_dentry)
|
||||
+ struct vfsmount *old_mnt, struct inode *new_dir,
|
||||
+ struct dentry *new_dentry, struct vfsmount *new_mnt)
|
||||
{
|
||||
struct inode *target;
|
||||
int error;
|
||||
@@ -2618,7 +2620,8 @@ static int vfs_rename_other(struct inode
|
||||
}
|
||||
|
||||
int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
- struct inode *new_dir, struct dentry *new_dentry)
|
||||
+ struct vfsmount *old_mnt, struct inode *new_dir,
|
||||
+ struct dentry *new_dentry, struct vfsmount *new_mnt)
|
||||
{
|
||||
int error;
|
||||
int is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
|
||||
@@ -2647,9 +2650,11 @@ int vfs_rename(struct inode *old_dir, st
|
||||
old_name = fsnotify_oldname_init(old_dentry->d_name.name);
|
||||
|
||||
if (is_dir)
|
||||
- error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
|
||||
+ error = vfs_rename_dir(old_dir, old_dentry, old_mnt,
|
||||
+ new_dir, new_dentry, new_mnt);
|
||||
else
|
||||
- error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
|
||||
+ error = vfs_rename_other(old_dir, old_dentry, old_mnt,
|
||||
+ new_dir, new_dentry, new_mnt);
|
||||
if (!error) {
|
||||
const char *new_name = old_dentry->d_name.name;
|
||||
fsnotify_move(old_dir, new_dir, old_name, new_name, is_dir,
|
||||
@@ -2726,8 +2731,8 @@ SYSCALL_DEFINE4(renameat, int, olddfd, c
|
||||
error = mnt_want_write(oldnd.path.mnt);
|
||||
if (error)
|
||||
goto exit5;
|
||||
- error = vfs_rename(old_dir->d_inode, old_dentry,
|
||||
- new_dir->d_inode, new_dentry);
|
||||
+ error = vfs_rename(old_dir->d_inode, old_dentry, oldnd.path.mnt,
|
||||
+ new_dir->d_inode, new_dentry, newnd.path.mnt);
|
||||
mnt_drop_write(oldnd.path.mnt);
|
||||
exit5:
|
||||
dput(new_dentry);
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1752,7 +1752,8 @@ nfsd_rename(struct svc_rqst *rqstp, stru
|
||||
if (host_err)
|
||||
goto out_dput_new;
|
||||
|
||||
- host_err = vfs_rename(fdir, odentry, tdir, ndentry);
|
||||
+ host_err = vfs_rename(fdir, odentry, ffhp->fh_export->ex_path.mnt,
|
||||
+ tdir, ndentry, tfhp->fh_export->ex_path.mnt);
|
||||
if (!host_err && EX_ISSYNC(tfhp->fh_export)) {
|
||||
host_err = nfsd_sync_dir(tdentry);
|
||||
if (!host_err)
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1184,7 +1184,7 @@ extern int vfs_symlink(struct inode *, s
|
||||
extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
|
||||
extern int vfs_rmdir(struct inode *, struct dentry *, struct vfsmount *);
|
||||
extern int vfs_unlink(struct inode *, struct dentry *, struct vfsmount *);
|
||||
-extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
|
||||
+extern int vfs_rename(struct inode *, struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
|
||||
|
||||
/*
|
||||
* VFS dentry helper functions.
|
||||
@@ -1,123 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_rmdir()
|
||||
|
||||
The vfsmount will be passed down to the LSM hook so that LSMs can compute
|
||||
pathnames.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/ecryptfs/inode.c | 4 +++-
|
||||
fs/namei.c | 4 ++--
|
||||
fs/nfsd/nfs4recover.c | 2 +-
|
||||
fs/nfsd/vfs.c | 8 +++++---
|
||||
include/linux/fs.h | 2 +-
|
||||
5 files changed, 12 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -534,14 +534,16 @@ out:
|
||||
static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct dentry *lower_dentry;
|
||||
+ struct vfsmount *lower_mnt;
|
||||
struct dentry *lower_dir_dentry;
|
||||
int rc;
|
||||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
dget(dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
dget(lower_dentry);
|
||||
- rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
|
||||
+ rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry, lower_mnt);
|
||||
dput(lower_dentry);
|
||||
if (!rc)
|
||||
d_delete(lower_dentry);
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2167,7 +2167,7 @@ void dentry_unhash(struct dentry *dentry
|
||||
spin_unlock(&dcache_lock);
|
||||
}
|
||||
|
||||
-int vfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
+int vfs_rmdir(struct inode *dir, struct dentry *dentry,struct vfsmount *mnt)
|
||||
{
|
||||
int error = may_delete(dir, dentry, 1);
|
||||
|
||||
@@ -2230,7 +2230,7 @@ static long do_rmdir(int dfd, const char
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto exit3;
|
||||
- error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
|
||||
+ error = vfs_rmdir(nd.path.dentry->d_inode, dentry, nd.path.mnt);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
exit3:
|
||||
dput(dentry);
|
||||
--- a/fs/nfsd/nfs4recover.c
|
||||
+++ b/fs/nfsd/nfs4recover.c
|
||||
@@ -279,7 +279,7 @@ nfsd4_clear_clid_dir(struct dentry *dir,
|
||||
* a kernel from the future.... */
|
||||
nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file);
|
||||
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
- status = vfs_rmdir(dir->d_inode, dentry);
|
||||
+ status = vfs_rmdir(dir->d_inode, dentry, rec_dir.path.mnt);
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
return status;
|
||||
}
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1790,6 +1790,7 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
|
||||
char *fname, int flen)
|
||||
{
|
||||
struct dentry *dentry, *rdentry;
|
||||
+ struct svc_export *exp;
|
||||
struct inode *dirp;
|
||||
__be32 err;
|
||||
int host_err;
|
||||
@@ -1804,6 +1805,7 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
|
||||
fh_lock_nested(fhp, I_MUTEX_PARENT);
|
||||
dentry = fhp->fh_dentry;
|
||||
dirp = dentry->d_inode;
|
||||
+ exp = fhp->fh_export;
|
||||
|
||||
rdentry = lookup_one_len(fname, dentry, flen);
|
||||
host_err = PTR_ERR(rdentry);
|
||||
@@ -1825,21 +1827,21 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
|
||||
|
||||
if (type != S_IFDIR) { /* It's UNLINK */
|
||||
#ifdef MSNFS
|
||||
- if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
|
||||
+ if ((exp->ex_flags & NFSEXP_MSNFS) &&
|
||||
(atomic_read(&rdentry->d_count) > 1)) {
|
||||
host_err = -EPERM;
|
||||
} else
|
||||
#endif
|
||||
host_err = vfs_unlink(dirp, rdentry);
|
||||
} else { /* It's RMDIR */
|
||||
- host_err = vfs_rmdir(dirp, rdentry);
|
||||
+ host_err = vfs_rmdir(dirp, rdentry, exp->ex_path.mnt);
|
||||
}
|
||||
|
||||
dput(rdentry);
|
||||
|
||||
if (host_err)
|
||||
goto out_drop;
|
||||
- if (EX_ISSYNC(fhp->fh_export))
|
||||
+ if (EX_ISSYNC(exp))
|
||||
host_err = nfsd_sync_dir(dentry);
|
||||
|
||||
out_drop:
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1182,7 +1182,7 @@ extern int vfs_mkdir(struct inode *, str
|
||||
extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t);
|
||||
extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *);
|
||||
extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
|
||||
-extern int vfs_rmdir(struct inode *, struct dentry *);
|
||||
+extern int vfs_rmdir(struct inode *, struct dentry *, struct vfsmount *);
|
||||
extern int vfs_unlink(struct inode *, struct dentry *);
|
||||
extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_setxattr()
|
||||
|
||||
The vfsmount will be passed down to the LSM hook so that LSMs can compute
|
||||
pathnames.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/nfsd/vfs.c | 16 +++++++++++-----
|
||||
fs/xattr.c | 16 ++++++++--------
|
||||
include/linux/xattr.h | 3 ++-
|
||||
3 files changed, 21 insertions(+), 14 deletions(-)
|
||||
|
||||
Index: linux-2.6.27/fs/nfsd/vfs.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/fs/nfsd/vfs.c
|
||||
+++ linux-2.6.27/fs/nfsd/vfs.c
|
||||
@@ -438,7 +438,8 @@ static ssize_t nfsd_getxattr(struct dent
|
||||
|
||||
#if defined(CONFIG_NFSD_V4)
|
||||
static int
|
||||
-set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
|
||||
+set_nfsv4_acl_one(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct posix_acl *pacl, char *key)
|
||||
{
|
||||
int len;
|
||||
size_t buflen;
|
||||
@@ -457,7 +458,7 @@ set_nfsv4_acl_one(struct dentry *dentry,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- error = vfs_setxattr(dentry, key, buf, len, 0);
|
||||
+ error = vfs_setxattr(dentry, mnt, key, buf, len, 0);
|
||||
out:
|
||||
kfree(buf);
|
||||
return error;
|
||||
@@ -470,6 +471,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst
|
||||
__be32 error;
|
||||
int host_error;
|
||||
struct dentry *dentry;
|
||||
+ struct vfsmount *mnt;
|
||||
struct inode *inode;
|
||||
struct posix_acl *pacl = NULL, *dpacl = NULL;
|
||||
unsigned int flags = 0;
|
||||
@@ -480,6 +482,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst
|
||||
return error;
|
||||
|
||||
dentry = fhp->fh_dentry;
|
||||
+ mnt = fhp->fh_export->ex_path.mnt;
|
||||
inode = dentry->d_inode;
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
flags = NFS4_ACL_DIR;
|
||||
@@ -490,12 +493,14 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst
|
||||
} else if (host_error < 0)
|
||||
goto out_nfserr;
|
||||
|
||||
- host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
|
||||
+ host_error = set_nfsv4_acl_one(dentry, mnt, pacl,
|
||||
+ POSIX_ACL_XATTR_ACCESS);
|
||||
if (host_error < 0)
|
||||
goto out_release;
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
- host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
|
||||
+ host_error = set_nfsv4_acl_one(dentry, mnt, dpacl,
|
||||
+ POSIX_ACL_XATTR_DEFAULT);
|
||||
|
||||
out_release:
|
||||
posix_acl_release(pacl);
|
||||
@@ -2123,7 +2128,8 @@ nfsd_set_posix_acl(struct svc_fh *fhp, i
|
||||
if (error)
|
||||
goto getout;
|
||||
if (size)
|
||||
- error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0);
|
||||
+ error = vfs_setxattr(fhp->fh_dentry, fhp->fh_export->ex_path.mnt,
|
||||
+ name, value, size,0);
|
||||
else {
|
||||
if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
|
||||
error = 0;
|
||||
Index: linux-2.6.27/fs/xattr.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/fs/xattr.c
|
||||
+++ linux-2.6.27/fs/xattr.c
|
||||
@@ -67,8 +67,8 @@ xattr_permission(struct inode *inode, co
|
||||
}
|
||||
|
||||
int
|
||||
-vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
||||
- size_t size, int flags)
|
||||
+vfs_setxattr(struct dentry *dentry, struct vfsmount *mnt, const char *name,
|
||||
+ const void *value, size_t size, int flags)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -218,8 +218,8 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
|
||||
* Extended attribute SET operations
|
||||
*/
|
||||
static long
|
||||
-setxattr(struct dentry *d, const char __user *name, const void __user *value,
|
||||
- size_t size, int flags)
|
||||
+setxattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name,
|
||||
+ const void __user *value, size_t size, int flags)
|
||||
{
|
||||
int error;
|
||||
void *kvalue = NULL;
|
||||
@@ -246,7 +246,7 @@ setxattr(struct dentry *d, const char __
|
||||
}
|
||||
}
|
||||
|
||||
- error = vfs_setxattr(d, kname, kvalue, size, flags);
|
||||
+ error = vfs_setxattr(dentry, mnt, kname, kvalue, size, flags);
|
||||
kfree(kvalue);
|
||||
return error;
|
||||
}
|
||||
@@ -263,7 +263,7 @@ SYSCALL_DEFINE5(setxattr, const char __u
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = setxattr(path.dentry, name, value, size, flags);
|
||||
+ error = setxattr(path.dentry, path.mnt, name, value, size, flags);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -282,7 +282,7 @@ SYSCALL_DEFINE5(lsetxattr, const char __
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = setxattr(path.dentry, name, value, size, flags);
|
||||
+ error = setxattr(path.dentry, path.mnt, name, value, size, flags);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -303,7 +303,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, cons
|
||||
audit_inode(NULL, dentry);
|
||||
error = mnt_want_write_file(f->f_path.mnt, f);
|
||||
if (!error) {
|
||||
- error = setxattr(dentry, name, value, size, flags);
|
||||
+ error = setxattr(dentry, f->f_vfsmnt, name, value, size, flags);
|
||||
mnt_drop_write(f->f_path.mnt);
|
||||
}
|
||||
fput(f);
|
||||
Index: linux-2.6.27/include/linux/xattr.h
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/include/linux/xattr.h
|
||||
+++ linux-2.6.27/include/linux/xattr.h
|
||||
@@ -16,6 +16,7 @@
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/types.h>
|
||||
+#include <linux/mount.h>
|
||||
|
||||
/* Namespaces */
|
||||
#define XATTR_OS2_PREFIX "os2."
|
||||
@@ -49,7 +50,7 @@ struct xattr_handler {
|
||||
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
|
||||
ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
|
||||
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
|
||||
-int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int);
|
||||
+int vfs_setxattr(struct dentry *, struct vfsmount *, const char *, const void *, size_t, int);
|
||||
int vfs_removexattr(struct dentry *, const char *);
|
||||
|
||||
ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size);
|
||||
@@ -1,123 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_symlink()
|
||||
|
||||
The vfsmount will be passed down to the LSM hook so that LSMs can compute
|
||||
pathnames.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/ecryptfs/inode.c | 4 +++-
|
||||
fs/namei.c | 5 +++--
|
||||
fs/nfsd/vfs.c | 12 ++++++++----
|
||||
include/linux/fs.h | 2 +-
|
||||
4 files changed, 15 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -464,6 +464,7 @@ static int ecryptfs_symlink(struct inode
|
||||
{
|
||||
int rc;
|
||||
struct dentry *lower_dentry;
|
||||
+ struct vfsmount *lower_mnt;
|
||||
struct dentry *lower_dir_dentry;
|
||||
char *encoded_symname;
|
||||
int encoded_symlen;
|
||||
@@ -471,6 +472,7 @@ static int ecryptfs_symlink(struct inode
|
||||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
dget(lower_dentry);
|
||||
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname,
|
||||
strlen(symname),
|
||||
@@ -479,7 +481,7 @@ static int ecryptfs_symlink(struct inode
|
||||
rc = encoded_symlen;
|
||||
goto out_lock;
|
||||
}
|
||||
- rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,
|
||||
+ rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry, lower_mnt,
|
||||
encoded_symname);
|
||||
kfree(encoded_symname);
|
||||
if (rc || !lower_dentry->d_inode)
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2347,7 +2347,8 @@ SYSCALL_DEFINE1(unlink, const char __use
|
||||
return do_unlinkat(AT_FDCWD, pathname);
|
||||
}
|
||||
|
||||
-int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
|
||||
+int vfs_symlink(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *oldname)
|
||||
{
|
||||
int error = may_create(dir, dentry, 0);
|
||||
|
||||
@@ -2393,7 +2394,7 @@ SYSCALL_DEFINE3(symlinkat, const char __
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
- error = vfs_symlink(nd.path.dentry->d_inode, dentry, from);
|
||||
+ error = vfs_symlink(nd.path.dentry->d_inode, dentry, nd.path.mnt, from);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
out_dput:
|
||||
dput(dentry);
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1545,6 +1545,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
|
||||
struct iattr *iap)
|
||||
{
|
||||
struct dentry *dentry, *dnew;
|
||||
+ struct svc_export *exp;
|
||||
__be32 err, cerr;
|
||||
int host_err;
|
||||
|
||||
@@ -1569,6 +1570,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
|
||||
if (host_err)
|
||||
goto out_nfserr;
|
||||
|
||||
+ exp = fhp->fh_export;
|
||||
if (unlikely(path[plen] != 0)) {
|
||||
char *path_alloced = kmalloc(plen+1, GFP_KERNEL);
|
||||
if (path_alloced == NULL)
|
||||
@@ -1576,14 +1578,16 @@ nfsd_symlink(struct svc_rqst *rqstp, str
|
||||
else {
|
||||
strncpy(path_alloced, path, plen);
|
||||
path_alloced[plen] = 0;
|
||||
- host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced);
|
||||
+ host_err = vfs_symlink(dentry->d_inode, dnew,
|
||||
+ exp->ex_path.mnt, path_alloced);
|
||||
kfree(path_alloced);
|
||||
}
|
||||
} else
|
||||
- host_err = vfs_symlink(dentry->d_inode, dnew, path);
|
||||
+ host_err = vfs_symlink(dentry->d_inode, dnew, exp->ex_path.mnt,
|
||||
+ path);
|
||||
|
||||
if (!host_err) {
|
||||
- if (EX_ISSYNC(fhp->fh_export))
|
||||
+ if (EX_ISSYNC(exp))
|
||||
host_err = nfsd_sync_dir(dentry);
|
||||
}
|
||||
err = nfserrno(host_err);
|
||||
@@ -1591,7 +1595,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
|
||||
|
||||
mnt_drop_write(fhp->fh_export->ex_path.mnt);
|
||||
|
||||
- cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
|
||||
+ cerr = fh_compose(resfhp, exp, dnew, fhp);
|
||||
dput(dnew);
|
||||
if (err==0) err = cerr;
|
||||
out:
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1180,7 +1180,7 @@ extern int vfs_permission(struct nameida
|
||||
extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
|
||||
extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int);
|
||||
extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t);
|
||||
-extern int vfs_symlink(struct inode *, struct dentry *, const char *);
|
||||
+extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *);
|
||||
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
|
||||
extern int vfs_rmdir(struct inode *, struct dentry *);
|
||||
extern int vfs_unlink(struct inode *, struct dentry *);
|
||||
@@ -1,100 +0,0 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_unlink()
|
||||
|
||||
The vfsmount will be passed down to the LSM hook so that LSMs can compute
|
||||
pathnames.
|
||||
|
||||
Signed-off-by: Tony Jones <tonyj@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/ecryptfs/inode.c | 3 ++-
|
||||
fs/namei.c | 4 ++--
|
||||
fs/nfsd/nfs4recover.c | 2 +-
|
||||
fs/nfsd/vfs.c | 2 +-
|
||||
include/linux/fs.h | 2 +-
|
||||
ipc/mqueue.c | 2 +-
|
||||
6 files changed, 8 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -445,12 +445,13 @@ static int ecryptfs_unlink(struct inode
|
||||
{
|
||||
int rc = 0;
|
||||
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
+ struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
|
||||
struct dentry *lower_dir_dentry;
|
||||
|
||||
dget(lower_dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
- rc = vfs_unlink(lower_dir_inode, lower_dentry);
|
||||
+ rc = vfs_unlink(lower_dir_inode, lower_dentry, lower_mnt);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
|
||||
goto out_unlock;
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2248,7 +2248,7 @@ SYSCALL_DEFINE1(rmdir, const char __user
|
||||
return do_rmdir(AT_FDCWD, pathname);
|
||||
}
|
||||
|
||||
-int vfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
+int vfs_unlink(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt)
|
||||
{
|
||||
int error = may_delete(dir, dentry, 0);
|
||||
|
||||
@@ -2313,7 +2313,7 @@ static long do_unlinkat(int dfd, const c
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto exit2;
|
||||
- error = vfs_unlink(nd.path.dentry->d_inode, dentry);
|
||||
+ error = vfs_unlink(nd.path.dentry->d_inode, dentry, nd.path.mnt);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
exit2:
|
||||
dput(dentry);
|
||||
--- a/fs/nfsd/nfs4recover.c
|
||||
+++ b/fs/nfsd/nfs4recover.c
|
||||
@@ -264,7 +264,7 @@ nfsd4_remove_clid_file(struct dentry *di
|
||||
return -EINVAL;
|
||||
}
|
||||
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
- status = vfs_unlink(dir->d_inode, dentry);
|
||||
+ status = vfs_unlink(dir->d_inode, dentry, rec_dir.path.mnt);
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
return status;
|
||||
}
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1833,7 +1833,7 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
|
||||
host_err = -EPERM;
|
||||
} else
|
||||
#endif
|
||||
- host_err = vfs_unlink(dirp, rdentry);
|
||||
+ host_err = vfs_unlink(dirp, rdentry, exp->ex_path.mnt);
|
||||
} else { /* It's RMDIR */
|
||||
host_err = vfs_rmdir(dirp, rdentry, exp->ex_path.mnt);
|
||||
}
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1183,7 +1183,7 @@ extern int vfs_mknod(struct inode *, str
|
||||
extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *);
|
||||
extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
|
||||
extern int vfs_rmdir(struct inode *, struct dentry *, struct vfsmount *);
|
||||
-extern int vfs_unlink(struct inode *, struct dentry *);
|
||||
+extern int vfs_unlink(struct inode *, struct dentry *, struct vfsmount *);
|
||||
extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
|
||||
|
||||
/*
|
||||
--- a/ipc/mqueue.c
|
||||
+++ b/ipc/mqueue.c
|
||||
@@ -746,7 +746,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __
|
||||
err = mnt_want_write(mqueue_mnt);
|
||||
if (err)
|
||||
goto out_err;
|
||||
- err = vfs_unlink(dentry->d_parent->d_inode, dentry);
|
||||
+ err = vfs_unlink(dentry->d_parent->d_inode, dentry, mqueue_mnt);
|
||||
mnt_drop_write(mqueue_mnt);
|
||||
out_err:
|
||||
dput(dentry);
|
||||
@@ -1,118 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: ACPI: video: Ignore devices that aren't present in hardware
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit ad9ed8385ed6ec5be8da7094db911c824258ceec
|
||||
|
||||
This is a reimplemention of commit
|
||||
0119509c4fbc9adcef1472817fda295334612976
|
||||
from Matthew Garrett <mjg59@srcf.ucam.org>
|
||||
|
||||
This patch got removed because of a regression: ThinkPads with a
|
||||
Intel graphics card and an Integrated Graphics Device BIOS implementation
|
||||
stopped working.
|
||||
In fact, they only worked because the ACPI device of the discrete, the
|
||||
wrong one, got used (via int10). So ACPI functions were poking on the wrong
|
||||
hardware used which is a sever bug.
|
||||
The next patch provides support for above ThinkPads to be able to
|
||||
switch brightness via the legacy thinkpad_acpi driver and automatically
|
||||
detect when to use it.
|
||||
|
||||
Original commit message from Matthew Garrett:
|
||||
Vendors often ship machines with a choice of integrated or discrete
|
||||
graphics, and use the same DSDT for both. As a result, the ACPI video
|
||||
module will locate devices that may not exist on this specific platform.
|
||||
Attempt to determine whether the device exists or not, and abort the
|
||||
device creation if it doesn't.
|
||||
|
||||
http://bugzilla.kernel.org/show_bug.cgi?id=9614
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
|
||||
---
|
||||
drivers/acpi/glue.c | 40 ++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/acpi/video.c | 7 ++++++-
|
||||
include/acpi/acpi_bus.h | 2 ++
|
||||
3 files changed, 48 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/acpi/glue.c
|
||||
+++ b/drivers/acpi/glue.c
|
||||
@@ -140,6 +140,46 @@ struct device *acpi_get_physical_device(
|
||||
|
||||
EXPORT_SYMBOL(acpi_get_physical_device);
|
||||
|
||||
+/* ToDo: When a PCI bridge is found, return the PCI device behind the bridge
|
||||
+ * This should work in general, but did not on a Lenovo T61 for the
|
||||
+ * graphics card. But this must be fixed when the PCI device is
|
||||
+ * bound and the kernel device struct is attached to the acpi device
|
||||
+ * Note: A success call will increase reference count by one
|
||||
+ * Do call put_device(dev) on the returned device then
|
||||
+ */
|
||||
+struct device *acpi_get_physical_pci_device(acpi_handle handle)
|
||||
+{
|
||||
+ struct device *dev;
|
||||
+ long long device_id;
|
||||
+ acpi_status status;
|
||||
+
|
||||
+ status =
|
||||
+ acpi_evaluate_integer(handle, "_ADR", NULL, &device_id);
|
||||
+
|
||||
+ if (ACPI_FAILURE(status))
|
||||
+ return NULL;
|
||||
+
|
||||
+ /* We need to attempt to determine whether the _ADR refers to a
|
||||
+ PCI device or not. There's no terribly good way to do this,
|
||||
+ so the best we can hope for is to assume that there'll never
|
||||
+ be a device in the host bridge */
|
||||
+ if (device_id >= 0x10000) {
|
||||
+ /* It looks like a PCI device. Does it exist? */
|
||||
+ dev = acpi_get_physical_device(handle);
|
||||
+ } else {
|
||||
+ /* It doesn't look like a PCI device. Does its parent
|
||||
+ exist? */
|
||||
+ acpi_handle phandle;
|
||||
+ if (acpi_get_parent(handle, &phandle))
|
||||
+ return NULL;
|
||||
+ dev = acpi_get_physical_device(phandle);
|
||||
+ }
|
||||
+ if (!dev)
|
||||
+ return NULL;
|
||||
+ return dev;
|
||||
+}
|
||||
+EXPORT_SYMBOL(acpi_get_physical_pci_device);
|
||||
+
|
||||
static int acpi_bind_one(struct device *dev, acpi_handle handle)
|
||||
{
|
||||
struct acpi_device *acpi_dev;
|
||||
--- a/drivers/acpi/video.c
|
||||
+++ b/drivers/acpi/video.c
|
||||
@@ -862,11 +862,16 @@ static void acpi_video_bus_find_cap(stru
|
||||
static int acpi_video_bus_check(struct acpi_video_bus *video)
|
||||
{
|
||||
acpi_status status = -ENOENT;
|
||||
-
|
||||
+ struct device *dev;
|
||||
|
||||
if (!video)
|
||||
return -EINVAL;
|
||||
|
||||
+ dev = acpi_get_physical_pci_device(video->device->handle);
|
||||
+ if (!dev)
|
||||
+ return -ENODEV;
|
||||
+ put_device(dev);
|
||||
+
|
||||
/* Since there is no HID, CID and so on for VGA driver, we have
|
||||
* to check well known required nodes.
|
||||
*/
|
||||
--- a/include/acpi/acpi_bus.h
|
||||
+++ b/include/acpi/acpi_bus.h
|
||||
@@ -373,6 +373,8 @@ struct acpi_bus_type {
|
||||
int register_acpi_bus_type(struct acpi_bus_type *);
|
||||
int unregister_acpi_bus_type(struct acpi_bus_type *);
|
||||
struct device *acpi_get_physical_device(acpi_handle);
|
||||
+struct device *acpi_get_physical_pci_device(acpi_handle);
|
||||
+
|
||||
/* helper */
|
||||
acpi_handle acpi_get_child(acpi_handle, acpi_integer);
|
||||
acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
|
||||
@@ -1,489 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] Check for ACPI backlight support otherwise use vendor ACPI drivers
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit f43d728731c691772ddc29e50d25c68a859935b5
|
||||
|
||||
If an ACPI graphics device supports backlight brightness functions (cmp. with
|
||||
latest ACPI spec Appendix B), let the ACPI video driver control backlight and
|
||||
switch backlight control off in vendor specific ACPI drivers (asus_acpi,
|
||||
thinkpad_acpi, eeepc, fujitsu_laptop, msi_laptop, sony_laptop, acer-wmi).
|
||||
|
||||
Currently it is possible to load above drivers and let both poke on the
|
||||
brightness HW registers, the video and vendor specific ACPI drivers -> bad.
|
||||
|
||||
This patch provides the basic support to check for BIOS capabilities before
|
||||
driver loading time. Driver specific modifications are in separate follow up
|
||||
patches.
|
||||
|
||||
acpi_backlight=vendor/video
|
||||
boot params forces video.ko or vendor specific drivers to keep its
|
||||
fingers off backlight control even it would find needed functions.
|
||||
The corresponding vendor specific driver be used then.
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
Documentation/kernel-parameters.txt | 13 +
|
||||
drivers/acpi/Makefile | 5
|
||||
drivers/acpi/scan.c | 32 ----
|
||||
drivers/acpi/video.c | 28 ++-
|
||||
drivers/acpi/video_detect.c | 268 ++++++++++++++++++++++++++++++++++++
|
||||
include/linux/acpi.h | 44 +++++
|
||||
6 files changed, 347 insertions(+), 43 deletions(-)
|
||||
create mode 100644 drivers/acpi/video_detect.c
|
||||
|
||||
--- a/Documentation/kernel-parameters.txt
|
||||
+++ b/Documentation/kernel-parameters.txt
|
||||
@@ -200,6 +200,19 @@ and is between 256 and 4096 characters.
|
||||
that require a timer override, but don't have
|
||||
HPET
|
||||
|
||||
+ acpi_backlight= [HW,ACPI]
|
||||
+ acpi_backlight=vendor
|
||||
+ acpi_backlight=video
|
||||
+ If set to vendor, it enforces the use of a
|
||||
+ vendor specific ACPI driver for backlight switching
|
||||
+ (e.g. thinkpad_acpi, sony_acpi, etc.) instead
|
||||
+ of the video.ko driver.
|
||||
+
|
||||
+ acpi_display_output= [HW,ACPI]
|
||||
+ acpi_display_output=vendor
|
||||
+ acpi_display_output=video
|
||||
+ See above.
|
||||
+
|
||||
acpi.debug_layer= [HW,ACPI]
|
||||
Format: <int>
|
||||
Each bit of the <int> indicates an ACPI debug layer,
|
||||
--- a/drivers/acpi/Makefile
|
||||
+++ b/drivers/acpi/Makefile
|
||||
@@ -46,7 +46,12 @@ obj-$(CONFIG_ACPI_BUTTON) += button.o
|
||||
obj-$(CONFIG_ACPI_FAN) += fan.o
|
||||
obj-$(CONFIG_ACPI_DOCK) += dock.o
|
||||
obj-$(CONFIG_ACPI_BAY) += bay.o
|
||||
+
|
||||
obj-$(CONFIG_ACPI_VIDEO) += video.o
|
||||
+ifdef CONFIG_ACPI_VIDEO
|
||||
+obj-y += video_detect.o
|
||||
+endif
|
||||
+
|
||||
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
|
||||
obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
|
||||
obj-$(CONFIG_ACPI_POWER) += power.o
|
||||
--- a/drivers/acpi/scan.c
|
||||
+++ b/drivers/acpi/scan.c
|
||||
@@ -908,36 +908,6 @@ static void acpi_device_get_busid(struct
|
||||
}
|
||||
}
|
||||
|
||||
-static int
|
||||
-acpi_video_bus_match(struct acpi_device *device)
|
||||
-{
|
||||
- acpi_handle h_dummy;
|
||||
-
|
||||
- if (!device)
|
||||
- return -EINVAL;
|
||||
-
|
||||
- /* Since there is no HID, CID for ACPI Video drivers, we have
|
||||
- * to check well known required nodes for each feature we support.
|
||||
- */
|
||||
-
|
||||
- /* Does this device able to support video switching ? */
|
||||
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
|
||||
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
|
||||
- return 0;
|
||||
-
|
||||
- /* Does this device able to retrieve a video ROM ? */
|
||||
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
|
||||
- return 0;
|
||||
-
|
||||
- /* Does this device able to configure which video head to be POSTed ? */
|
||||
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
|
||||
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
|
||||
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
|
||||
- return 0;
|
||||
-
|
||||
- return -ENODEV;
|
||||
-}
|
||||
-
|
||||
/*
|
||||
* acpi_bay_match - see if a device is an ejectable driver bay
|
||||
*
|
||||
@@ -1020,7 +990,7 @@ static void acpi_device_set_id(struct ac
|
||||
will get autoloaded and the device might still match
|
||||
against another driver.
|
||||
*/
|
||||
- if (ACPI_SUCCESS(acpi_video_bus_match(device)))
|
||||
+ if (acpi_is_video_device(device))
|
||||
cid_add = ACPI_VIDEO_HID;
|
||||
else if (ACPI_SUCCESS(acpi_bay_match(device)))
|
||||
cid_add = ACPI_BAY_HID;
|
||||
--- a/drivers/acpi/video.c
|
||||
+++ b/drivers/acpi/video.c
|
||||
@@ -759,7 +759,8 @@ static void acpi_video_device_find_cap(s
|
||||
device->cap._DSS = 1;
|
||||
}
|
||||
|
||||
- max_level = acpi_video_init_brightness(device);
|
||||
+ if (acpi_video_backlight_support())
|
||||
+ max_level = acpi_video_init_brightness(device);
|
||||
|
||||
if (device->cap._BCL && device->cap._BCM && max_level > 0) {
|
||||
int result;
|
||||
@@ -805,18 +806,21 @@ static void acpi_video_device_find_cap(s
|
||||
printk(KERN_ERR PREFIX "Create sysfs link\n");
|
||||
|
||||
}
|
||||
- if (device->cap._DCS && device->cap._DSS){
|
||||
- static int count = 0;
|
||||
- char *name;
|
||||
- name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
|
||||
- if (!name)
|
||||
- return;
|
||||
- sprintf(name, "acpi_video%d", count++);
|
||||
- device->output_dev = video_output_register(name,
|
||||
- NULL, device, &acpi_output_properties);
|
||||
- kfree(name);
|
||||
+
|
||||
+ if (acpi_video_display_switch_support()) {
|
||||
+
|
||||
+ if (device->cap._DCS && device->cap._DSS) {
|
||||
+ static int count;
|
||||
+ char *name;
|
||||
+ name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
|
||||
+ if (!name)
|
||||
+ return;
|
||||
+ sprintf(name, "acpi_video%d", count++);
|
||||
+ device->output_dev = video_output_register(name,
|
||||
+ NULL, device, &acpi_output_properties);
|
||||
+ kfree(name);
|
||||
+ }
|
||||
}
|
||||
- return;
|
||||
}
|
||||
|
||||
/*
|
||||
--- /dev/null
|
||||
+++ b/drivers/acpi/video_detect.c
|
||||
@@ -0,0 +1,268 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2008 SuSE Linux Products GmbH
|
||||
+ * Thomas Renninger <trenn@suse.de>
|
||||
+ *
|
||||
+ * May be copied or modified under the terms of the GNU General Public License
|
||||
+ *
|
||||
+ * video_detect.c:
|
||||
+ * Provides acpi_is_video_device() for early scanning of ACPI devices in scan.c
|
||||
+ * There a Linux specific (Spec does not provide a HID for video devices) is
|
||||
+ * assinged
|
||||
+ *
|
||||
+ * After PCI devices are glued with ACPI devices
|
||||
+ * acpi_get_physical_pci_device() can be called to identify ACPI graphics
|
||||
+ * devices for which a real graphics card is plugged in
|
||||
+ *
|
||||
+ * Now acpi_video_get_capabilities() can be called to check which
|
||||
+ * capabilities the graphics cards plugged in support. The check for general
|
||||
+ * video capabilities will be triggered by the first caller of
|
||||
+ * acpi_video_get_capabilities(NULL); which will happen when the first
|
||||
+ * backlight (or display output) switching supporting driver calls:
|
||||
+ * acpi_video_backlight_support();
|
||||
+ *
|
||||
+ * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
|
||||
+ * are available, video.ko should be used to handle the device.
|
||||
+ *
|
||||
+ * Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi,
|
||||
+ * sony_acpi,... can take care about backlight brightness and display output
|
||||
+ * switching.
|
||||
+ *
|
||||
+ * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
|
||||
+ * this file will not be compiled, acpi_video_get_capabilities() and
|
||||
+ * acpi_video_backlight_support() will always return 0 and vendor specific
|
||||
+ * drivers always can handle backlight.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <linux/acpi.h>
|
||||
+#include <linux/dmi.h>
|
||||
+
|
||||
+ACPI_MODULE_NAME("video");
|
||||
+#define ACPI_VIDEO_COMPONENT 0x08000000
|
||||
+#define _COMPONENT ACPI_VIDEO_COMPONENT
|
||||
+
|
||||
+static long acpi_video_support;
|
||||
+static bool acpi_video_caps_checked;
|
||||
+
|
||||
+static acpi_status
|
||||
+acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
|
||||
+ void **retyurn_value)
|
||||
+{
|
||||
+ long *cap = context;
|
||||
+ acpi_handle h_dummy;
|
||||
+
|
||||
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) &&
|
||||
+ ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) {
|
||||
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
|
||||
+ "support\n"));
|
||||
+ *cap |= ACPI_VIDEO_BACKLIGHT;
|
||||
+ /* We have backlight support, no need to scan further */
|
||||
+ return AE_CTRL_TERMINATE;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Returns true if the device is a video device which can be handled by
|
||||
+ * video.ko.
|
||||
+ * The device will get a Linux specific CID added in scan.c to
|
||||
+ * identify the device as an ACPI graphics device
|
||||
+ * Be aware that the graphics device may not be physically present
|
||||
+ * Use acpi_video_get_capabilities() to detect general ACPI video
|
||||
+ * capabilities of present cards
|
||||
+ */
|
||||
+long acpi_is_video_device(struct acpi_device *device)
|
||||
+{
|
||||
+ acpi_handle h_dummy;
|
||||
+ long video_caps = 0;
|
||||
+
|
||||
+ if (!device)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* Does this device able to support video switching ? */
|
||||
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
|
||||
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
|
||||
+ video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
|
||||
+
|
||||
+ /* Does this device able to retrieve a video ROM ? */
|
||||
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
|
||||
+ video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
|
||||
+
|
||||
+ /* Does this device able to configure which video head to be POSTed ? */
|
||||
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
|
||||
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
|
||||
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
|
||||
+ video_caps |= ACPI_VIDEO_DEVICE_POSTING;
|
||||
+
|
||||
+ /* Only check for backlight functionality if one of the above hit. */
|
||||
+ if (video_caps)
|
||||
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle,
|
||||
+ ACPI_UINT32_MAX, acpi_backlight_cap_match,
|
||||
+ &video_caps, NULL);
|
||||
+
|
||||
+ return video_caps;
|
||||
+}
|
||||
+EXPORT_SYMBOL(acpi_is_video_device);
|
||||
+
|
||||
+static acpi_status
|
||||
+find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
+{
|
||||
+ long *cap = context;
|
||||
+ struct device *dev;
|
||||
+ struct acpi_device *acpi_dev;
|
||||
+
|
||||
+ const struct acpi_device_id video_ids[] = {
|
||||
+ {ACPI_VIDEO_HID, 0},
|
||||
+ {"", 0},
|
||||
+ };
|
||||
+ if (acpi_bus_get_device(handle, &acpi_dev))
|
||||
+ return AE_OK;
|
||||
+
|
||||
+ if (!acpi_match_device_ids(acpi_dev, video_ids)) {
|
||||
+ dev = acpi_get_physical_pci_device(handle);
|
||||
+ if (!dev)
|
||||
+ return AE_OK;
|
||||
+ put_device(dev);
|
||||
+ *cap |= acpi_is_video_device(acpi_dev);
|
||||
+ }
|
||||
+ return AE_OK;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Returns the video capabilities of a specific ACPI graphics device
|
||||
+ *
|
||||
+ * if NULL is passed as argument all ACPI devices are enumerated and
|
||||
+ * all graphics capabilities of physically present devices are
|
||||
+ * summerized and returned. This is cached and done only once.
|
||||
+ */
|
||||
+long acpi_video_get_capabilities(acpi_handle graphics_handle)
|
||||
+{
|
||||
+ long caps = 0;
|
||||
+ struct acpi_device *tmp_dev;
|
||||
+ acpi_status status;
|
||||
+
|
||||
+ if (acpi_video_caps_checked && graphics_handle == NULL)
|
||||
+ return acpi_video_support;
|
||||
+
|
||||
+ if (!graphics_handle) {
|
||||
+ /* Only do the global walk through all graphics devices once */
|
||||
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
+ ACPI_UINT32_MAX, find_video,
|
||||
+ &caps, NULL);
|
||||
+ /* There might be boot param flags set already... */
|
||||
+ acpi_video_support |= caps;
|
||||
+ acpi_video_caps_checked = 1;
|
||||
+ /* Add blacklists here. Be careful to use the right *DMI* bits
|
||||
+ * to still be able to override logic via boot params, e.g.:
|
||||
+ *
|
||||
+ * if (dmi_name_in_vendors("XY")) {
|
||||
+ * acpi_video_support |=
|
||||
+ * ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR;
|
||||
+ * acpi_video_support |=
|
||||
+ * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
|
||||
+ *}
|
||||
+ */
|
||||
+ } else {
|
||||
+ status = acpi_bus_get_device(graphics_handle, &tmp_dev);
|
||||
+ if (ACPI_FAILURE(status)) {
|
||||
+ ACPI_EXCEPTION((AE_INFO, status, "Invalid device"));
|
||||
+ return 0;
|
||||
+ }
|
||||
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle,
|
||||
+ ACPI_UINT32_MAX, find_video,
|
||||
+ &caps, NULL);
|
||||
+ }
|
||||
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n",
|
||||
+ graphics_handle ? caps : acpi_video_support,
|
||||
+ graphics_handle ? "on device " : "in general",
|
||||
+ graphics_handle ? acpi_device_bid(tmp_dev) : ""));
|
||||
+ return caps;
|
||||
+}
|
||||
+EXPORT_SYMBOL(acpi_video_get_capabilities);
|
||||
+
|
||||
+/* Returns true if video.ko can do backlight switching */
|
||||
+int acpi_video_backlight_support(void)
|
||||
+{
|
||||
+ /*
|
||||
+ * We must check whether the ACPI graphics device is physically plugged
|
||||
+ * in. Therefore this must be called after binding PCI and ACPI devices
|
||||
+ */
|
||||
+ if (!acpi_video_caps_checked)
|
||||
+ acpi_video_get_capabilities(NULL);
|
||||
+
|
||||
+ /* First check for boot param -> highest prio */
|
||||
+ if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR)
|
||||
+ return 0;
|
||||
+ else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO)
|
||||
+ return 1;
|
||||
+
|
||||
+ /* Then check for DMI blacklist -> second highest prio */
|
||||
+ if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR)
|
||||
+ return 0;
|
||||
+ else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO)
|
||||
+ return 1;
|
||||
+
|
||||
+ /* Then go the default way */
|
||||
+ return acpi_video_support & ACPI_VIDEO_BACKLIGHT;
|
||||
+}
|
||||
+EXPORT_SYMBOL(acpi_video_backlight_support);
|
||||
+
|
||||
+/*
|
||||
+ * Returns true if video.ko can do display output switching.
|
||||
+ * This does not work well/at all with binary graphics drivers
|
||||
+ * which disable system io ranges and do it on their own.
|
||||
+ */
|
||||
+int acpi_video_display_switch_support(void)
|
||||
+{
|
||||
+ if (!acpi_video_caps_checked)
|
||||
+ acpi_video_get_capabilities(NULL);
|
||||
+
|
||||
+ if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR)
|
||||
+ return 0;
|
||||
+ else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR)
|
||||
+ return 0;
|
||||
+ else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO)
|
||||
+ return 1;
|
||||
+
|
||||
+ return acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING;
|
||||
+}
|
||||
+EXPORT_SYMBOL(acpi_video_display_switch_support);
|
||||
+
|
||||
+/*
|
||||
+ * Use acpi_display_output=vendor/video or acpi_backlight=vendor/video
|
||||
+ * To force that backlight or display output switching is processed by vendor
|
||||
+ * specific acpi drivers or video.ko driver.
|
||||
+ */
|
||||
+int __init acpi_backlight(char *str)
|
||||
+{
|
||||
+ if (str == NULL || *str == '\0')
|
||||
+ return 1;
|
||||
+ else {
|
||||
+ if (!strcmp("vendor", str))
|
||||
+ acpi_video_support |=
|
||||
+ ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR;
|
||||
+ if (!strcmp("video", str))
|
||||
+ acpi_video_support |=
|
||||
+ ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("acpi_backlight=", acpi_backlight);
|
||||
+
|
||||
+int __init acpi_display_output(char *str)
|
||||
+{
|
||||
+ if (str == NULL || *str == '\0')
|
||||
+ return 1;
|
||||
+ else {
|
||||
+ if (!strcmp("vendor", str))
|
||||
+ acpi_video_support |=
|
||||
+ ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR;
|
||||
+ if (!strcmp("video", str))
|
||||
+ acpi_video_support |=
|
||||
+ ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("acpi_display_output=", acpi_display_output);
|
||||
--- a/include/linux/acpi.h
|
||||
+++ b/include/linux/acpi.h
|
||||
@@ -202,6 +202,50 @@ extern bool wmi_has_guid(const char *gui
|
||||
|
||||
#endif /* CONFIG_ACPI_WMI */
|
||||
|
||||
+#define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001
|
||||
+#define ACPI_VIDEO_DEVICE_POSTING 0x0002
|
||||
+#define ACPI_VIDEO_ROM_AVAILABLE 0x0004
|
||||
+#define ACPI_VIDEO_BACKLIGHT 0x0008
|
||||
+#define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR 0x0010
|
||||
+#define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO 0x0020
|
||||
+#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR 0x0040
|
||||
+#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO 0x0080
|
||||
+#define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 0x0100
|
||||
+#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200
|
||||
+#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400
|
||||
+#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800
|
||||
+
|
||||
+#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
|
||||
+
|
||||
+extern long acpi_video_get_capabilities(acpi_handle graphics_dev_handle);
|
||||
+extern long acpi_is_video_device(struct acpi_device *device);
|
||||
+extern int acpi_video_backlight_support(void);
|
||||
+extern int acpi_video_display_switch_support(void);
|
||||
+
|
||||
+#else
|
||||
+
|
||||
+static inline long acpi_video_get_capabilities(acpi_handle graphics_dev_handle)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline long acpi_is_video_device(struct acpi_device *device)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline int acpi_video_backlight_support(void)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline int acpi_video_display_switch_support(void)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#endif /* defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) */
|
||||
+
|
||||
extern int acpi_blacklisted(void);
|
||||
#ifdef CONFIG_DMI
|
||||
extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);
|
||||
@@ -1,27 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] Acer-WMI: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit 017f8ecd1cedb482392f0500ee3701b8c50a46f9
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/acer-wmi.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
--- a/drivers/misc/acer-wmi.c
|
||||
+++ b/drivers/misc/acer-wmi.c
|
||||
@@ -1242,6 +1242,12 @@ static int __init acer_wmi_init(void)
|
||||
|
||||
set_quirks();
|
||||
|
||||
+ if (!acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) {
|
||||
+ interface->capability &= ~ACER_CAP_BRIGHTNESS;
|
||||
+ printk(ACER_INFO "Brightness must be controlled by "
|
||||
+ "generic video driver\n");
|
||||
+ }
|
||||
+
|
||||
if (platform_driver_register(&acer_platform_driver)) {
|
||||
printk(ACER_ERR "Unable to register platform driver.\n");
|
||||
goto error_platform_register;
|
||||
@@ -1,31 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] asus-acpi: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit aaa47082a287d66fad32e3289e01bb9419ab18da
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/asus-laptop.c | 10 +++++++---
|
||||
1 file changed, 7 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/misc/asus-laptop.c
|
||||
+++ b/drivers/misc/asus-laptop.c
|
||||
@@ -1208,9 +1208,13 @@ static int __init asus_laptop_init(void)
|
||||
|
||||
dev = acpi_get_physical_device(hotk->device->handle);
|
||||
|
||||
- result = asus_backlight_init(dev);
|
||||
- if (result)
|
||||
- goto fail_backlight;
|
||||
+ if (!acpi_video_backlight_support()) {
|
||||
+ result = asus_backlight_init(dev);
|
||||
+ if (result)
|
||||
+ goto fail_backlight;
|
||||
+ } else
|
||||
+ printk(ASUS_INFO "Brightness ignored, must be controlled by "
|
||||
+ "ACPI video driver\n");
|
||||
|
||||
result = asus_led_init(dev);
|
||||
if (result)
|
||||
@@ -1,39 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] compal: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit efbc58e3236022d040e1c1f177ee5971d46b034f
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/compal-laptop.c | 12 +++++++-----
|
||||
1 files changed, 7 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/misc/compal-laptop.c b/drivers/misc/compal-laptop.c
|
||||
index 344b790..11003bb 100644
|
||||
--- a/drivers/misc/compal-laptop.c
|
||||
+++ b/drivers/misc/compal-laptop.c
|
||||
@@ -326,12 +326,14 @@ static int __init compal_init(void)
|
||||
|
||||
/* Register backlight stuff */
|
||||
|
||||
- compalbl_device = backlight_device_register("compal-laptop", NULL, NULL,
|
||||
- &compalbl_ops);
|
||||
- if (IS_ERR(compalbl_device))
|
||||
- return PTR_ERR(compalbl_device);
|
||||
+ if (!acpi_video_backlight_support()) {
|
||||
+ compalbl_device = backlight_device_register("compal-laptop", NULL, NULL,
|
||||
+ &compalbl_ops);
|
||||
+ if (IS_ERR(compalbl_device))
|
||||
+ return PTR_ERR(compalbl_device);
|
||||
|
||||
- compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1;
|
||||
+ compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1;
|
||||
+ }
|
||||
|
||||
ret = platform_driver_register(&compal_driver);
|
||||
if (ret)
|
||||
--
|
||||
1.5.4.5
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] eeepc-laptop: fingers off backlight if video.ko is serving this functionality
|
||||
commit bb7e1665304cba64b1178237c966308d06b33182
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/eeepc-laptop.c | 12 +++++++++---
|
||||
1 file changed, 9 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/misc/eeepc-laptop.c
|
||||
+++ b/drivers/misc/eeepc-laptop.c
|
||||
@@ -636,9 +636,15 @@ static int __init eeepc_laptop_init(void
|
||||
return -ENODEV;
|
||||
}
|
||||
dev = acpi_get_physical_device(ehotk->device->handle);
|
||||
- result = eeepc_backlight_init(dev);
|
||||
- if (result)
|
||||
- goto fail_backlight;
|
||||
+
|
||||
+ if (!acpi_video_backlight_support()) {
|
||||
+ result = eeepc_backlight_init(dev);
|
||||
+ if (result)
|
||||
+ goto fail_backlight;
|
||||
+ } else
|
||||
+ printk(EEEPC_INFO "Backlight controlled by ACPI video "
|
||||
+ "driver\n");
|
||||
+
|
||||
result = eeepc_hwmon_init(dev);
|
||||
if (result)
|
||||
goto fail_hwmon;
|
||||
@@ -1,61 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] fujitsu-laptop: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit 44cce15b053d27477980e34b1086e0c3ce642afe
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/fujitsu-laptop.c | 26 ++++++++++++++------------
|
||||
1 file changed, 14 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/misc/fujitsu-laptop.c
|
||||
+++ b/drivers/misc/fujitsu-laptop.c
|
||||
@@ -970,16 +970,16 @@ static int __init fujitsu_init(void)
|
||||
|
||||
/* Register backlight stuff */
|
||||
|
||||
- fujitsu->bl_device =
|
||||
- backlight_device_register("fujitsu-laptop", NULL, NULL,
|
||||
- &fujitsubl_ops);
|
||||
- if (IS_ERR(fujitsu->bl_device))
|
||||
- return PTR_ERR(fujitsu->bl_device);
|
||||
-
|
||||
- max_brightness = fujitsu->max_brightness;
|
||||
-
|
||||
- fujitsu->bl_device->props.max_brightness = max_brightness - 1;
|
||||
- fujitsu->bl_device->props.brightness = fujitsu->brightness_level;
|
||||
+ if (!acpi_video_backlight_support()) {
|
||||
+ fujitsu->bl_device =
|
||||
+ backlight_device_register("fujitsu-laptop", NULL, NULL,
|
||||
+ &fujitsubl_ops);
|
||||
+ if (IS_ERR(fujitsu->bl_device))
|
||||
+ return PTR_ERR(fujitsu->bl_device);
|
||||
+ max_brightness = fujitsu->max_brightness;
|
||||
+ fujitsu->bl_device->props.max_brightness = max_brightness - 1;
|
||||
+ fujitsu->bl_device->props.brightness = fujitsu->brightness_level;
|
||||
+ }
|
||||
|
||||
ret = platform_driver_register(&fujitsupf_driver);
|
||||
if (ret)
|
||||
@@ -1015,7 +1015,8 @@ fail_hotkey:
|
||||
|
||||
fail_backlight:
|
||||
|
||||
- backlight_device_unregister(fujitsu->bl_device);
|
||||
+ if (fujitsu->bl_device)
|
||||
+ backlight_device_unregister(fujitsu->bl_device);
|
||||
|
||||
fail_platform_device2:
|
||||
|
||||
@@ -1042,7 +1043,8 @@ static void __exit fujitsu_cleanup(void)
|
||||
&fujitsupf_attribute_group);
|
||||
platform_device_unregister(fujitsu->pf_device);
|
||||
platform_driver_unregister(&fujitsupf_driver);
|
||||
- backlight_device_unregister(fujitsu->bl_device);
|
||||
+ if (fujitsu->bl_device)
|
||||
+ backlight_device_unregister(fujitsu->bl_device);
|
||||
|
||||
acpi_bus_unregister_driver(&acpi_fujitsu_driver);
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] msi-laptop: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit a8c338259a436627d2427d70dc31fac67b86b9e6
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/msi-laptop.c | 16 ++++++++++------
|
||||
1 files changed, 10 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
|
||||
index de898c6..759763d 100644
|
||||
--- a/drivers/misc/msi-laptop.c
|
||||
+++ b/drivers/misc/msi-laptop.c
|
||||
@@ -347,12 +347,16 @@ static int __init msi_init(void)
|
||||
|
||||
/* Register backlight stuff */
|
||||
|
||||
- msibl_device = backlight_device_register("msi-laptop-bl", NULL, NULL,
|
||||
- &msibl_ops);
|
||||
- if (IS_ERR(msibl_device))
|
||||
- return PTR_ERR(msibl_device);
|
||||
-
|
||||
- msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1;
|
||||
+ if (acpi_video_backlight_support()) {
|
||||
+ printk(KERN_INFO "MSI: Brightness ignored, must be controlled "
|
||||
+ "by ACPI video driver\n");
|
||||
+ } else {
|
||||
+ msibl_device = backlight_device_register("msi-laptop-bl", NULL,
|
||||
+ NULL, &msibl_ops);
|
||||
+ if (IS_ERR(msibl_device))
|
||||
+ return PTR_ERR(msibl_device);
|
||||
+ msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1;
|
||||
+ }
|
||||
|
||||
ret = platform_driver_register(&msipf_driver);
|
||||
if (ret)
|
||||
--
|
||||
1.5.4.5
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] sony-laptop: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit 1d38a0697573617e7f4d184207cced6cbe8d54d5
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/sony-laptop.c | 6 +++++-
|
||||
1 files changed, 5 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
|
||||
index 60775be..3d178ab 100644
|
||||
--- a/drivers/misc/sony-laptop.c
|
||||
+++ b/drivers/misc/sony-laptop.c
|
||||
@@ -1038,7 +1038,11 @@ static int sony_nc_add(struct acpi_device *device)
|
||||
goto outinput;
|
||||
}
|
||||
|
||||
- if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) {
|
||||
+ if (acpi_video_backlight_support()) {
|
||||
+ printk(KERN_INFO DRV_PFX "Sony: Brightness ignored, must be "
|
||||
+ "controlled by ACPI video driver\n");
|
||||
+ } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
|
||||
+ &handle))) {
|
||||
sony_backlight_device = backlight_device_register("sony", NULL,
|
||||
NULL,
|
||||
&sony_backlight_ops);
|
||||
--
|
||||
1.5.4.5
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] thinkpad_acpi: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit bcca9a4a97b6e270793003d745d6f9439e1357a8
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/thinkpad_acpi.c | 29 +++++++++++++++++++----------
|
||||
1 file changed, 19 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/misc/thinkpad_acpi.c
|
||||
+++ b/drivers/misc/thinkpad_acpi.c
|
||||
@@ -4918,16 +4918,25 @@ static int __init brightness_init(struct
|
||||
*/
|
||||
b = tpacpi_check_std_acpi_brightness_support();
|
||||
if (b > 0) {
|
||||
- if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
|
||||
- printk(TPACPI_NOTICE
|
||||
- "Lenovo BIOS switched to ACPI backlight "
|
||||
- "control mode\n");
|
||||
- }
|
||||
- if (brightness_enable > 1) {
|
||||
- printk(TPACPI_NOTICE
|
||||
- "standard ACPI backlight interface "
|
||||
- "available, not loading native one...\n");
|
||||
- return 1;
|
||||
+
|
||||
+ if (acpi_video_backlight_support()) {
|
||||
+ if (brightness_enable > 1) {
|
||||
+ printk(TPACPI_NOTICE
|
||||
+ "Standard ACPI backlight interface "
|
||||
+ "available, not loading native one.\n");
|
||||
+ return 1;
|
||||
+ } else if (brightness_enable == 1) {
|
||||
+ printk(TPACPI_NOTICE
|
||||
+ "Backlight control force, even standard "
|
||||
+ "ACPI backlight interface available\n");
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (brightness_enable > 1) {
|
||||
+ printk(TPACPI_NOTICE
|
||||
+ "Standard ACPI backlight interface not "
|
||||
+ "available, thinkpad_acpi driver "
|
||||
+ "will take over control\n");
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: acpi: remove bay.c from makefile
|
||||
|
||||
patches.fixes/acpi-bay-remove-useless-code.patch removed drivers/acpi/bay.c.
|
||||
This patch removes the build infrastructure for it.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
drivers/acpi/Kconfig | 8 --------
|
||||
drivers/acpi/Makefile | 1 -
|
||||
2 files changed, 9 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/Kconfig
|
||||
+++ b/drivers/acpi/Kconfig
|
||||
@@ -162,14 +162,6 @@ config ACPI_DOCK
|
||||
help
|
||||
This driver adds support for ACPI controlled docking stations
|
||||
|
||||
-config ACPI_BAY
|
||||
- tristate "Removable Drive Bay (EXPERIMENTAL)"
|
||||
- depends on EXPERIMENTAL
|
||||
- depends on ACPI_DOCK
|
||||
- help
|
||||
- This driver adds support for ACPI controlled removable drive
|
||||
- bays such as the IBM ultrabay or the Dell Module Bay.
|
||||
-
|
||||
config ACPI_PROCESSOR
|
||||
tristate "Processor"
|
||||
select THERMAL
|
||||
--- a/drivers/acpi/Makefile
|
||||
+++ b/drivers/acpi/Makefile
|
||||
@@ -45,7 +45,6 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o
|
||||
obj-$(CONFIG_ACPI_BUTTON) += button.o
|
||||
obj-$(CONFIG_ACPI_FAN) += fan.o
|
||||
obj-$(CONFIG_ACPI_DOCK) += dock.o
|
||||
-obj-$(CONFIG_ACPI_BAY) += bay.o
|
||||
|
||||
obj-$(CONFIG_ACPI_VIDEO) += video.o
|
||||
ifdef CONFIG_ACPI_VIDEO
|
||||
@@ -1,425 +0,0 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: remove useless code
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
Bay driver is replaced by dock driver, remove it.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
--- linux-2.6.26.orig/drivers/acpi/bay.c 2008-07-13 23:51:29.000000000 +0200
|
||||
+++ linux-2.6.26/drivers/acpi/bay.c 1970-01-01 01:00:00.000000000 +0100
|
||||
@@ -1,411 +0,0 @@
|
||||
-/*
|
||||
- * bay.c - ACPI removable drive bay driver
|
||||
- *
|
||||
- * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
|
||||
- *
|
||||
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
- *
|
||||
- * This program is free software; you can redistribute it and/or modify
|
||||
- * it under the terms of the GNU General Public License as published by
|
||||
- * the Free Software Foundation; either version 2 of the License, or (at
|
||||
- * your option) any later version.
|
||||
- *
|
||||
- * This program is distributed in the hope that it will be useful, but
|
||||
- * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
- * General Public License for more details.
|
||||
- *
|
||||
- * You should have received a copy of the GNU General Public License along
|
||||
- * with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
- *
|
||||
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
- */
|
||||
-#include <linux/kernel.h>
|
||||
-#include <linux/module.h>
|
||||
-#include <linux/init.h>
|
||||
-#include <linux/types.h>
|
||||
-#include <linux/notifier.h>
|
||||
-#include <acpi/acpi_bus.h>
|
||||
-#include <acpi/acpi_drivers.h>
|
||||
-#include <linux/seq_file.h>
|
||||
-#include <asm/uaccess.h>
|
||||
-#include <linux/platform_device.h>
|
||||
-
|
||||
-ACPI_MODULE_NAME("bay");
|
||||
-MODULE_AUTHOR("Kristen Carlson Accardi");
|
||||
-MODULE_DESCRIPTION("ACPI Removable Drive Bay Driver");
|
||||
-MODULE_LICENSE("GPL");
|
||||
-#define ACPI_BAY_CLASS "bay"
|
||||
-#define ACPI_BAY_COMPONENT 0x10000000
|
||||
-#define _COMPONENT ACPI_BAY_COMPONENT
|
||||
-#define bay_dprintk(h,s) {\
|
||||
- char prefix[80] = {'\0'};\
|
||||
- struct acpi_buffer buffer = {sizeof(prefix), prefix};\
|
||||
- acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
|
||||
- printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
|
||||
-static void bay_notify(acpi_handle handle, u32 event, void *data);
|
||||
-
|
||||
-static const struct acpi_device_id bay_device_ids[] = {
|
||||
- {"LNXIOBAY", 0},
|
||||
- {"", 0},
|
||||
-};
|
||||
-MODULE_DEVICE_TABLE(acpi, bay_device_ids);
|
||||
-
|
||||
-struct bay {
|
||||
- acpi_handle handle;
|
||||
- char *name;
|
||||
- struct list_head list;
|
||||
- struct platform_device *pdev;
|
||||
-};
|
||||
-
|
||||
-static LIST_HEAD(drive_bays);
|
||||
-
|
||||
-
|
||||
-/*****************************************************************************
|
||||
- * Drive Bay functions *
|
||||
- *****************************************************************************/
|
||||
-/**
|
||||
- * is_ejectable - see if a device is ejectable
|
||||
- * @handle: acpi handle of the device
|
||||
- *
|
||||
- * If an acpi object has a _EJ0 method, then it is ejectable
|
||||
- */
|
||||
-static int is_ejectable(acpi_handle handle)
|
||||
-{
|
||||
- acpi_status status;
|
||||
- acpi_handle tmp;
|
||||
-
|
||||
- status = acpi_get_handle(handle, "_EJ0", &tmp);
|
||||
- if (ACPI_FAILURE(status))
|
||||
- return 0;
|
||||
- return 1;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * bay_present - see if the bay device is present
|
||||
- * @bay: the drive bay
|
||||
- *
|
||||
- * execute the _STA method.
|
||||
- */
|
||||
-static int bay_present(struct bay *bay)
|
||||
-{
|
||||
- unsigned long long sta;
|
||||
- acpi_status status;
|
||||
-
|
||||
- if (bay) {
|
||||
- status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta);
|
||||
- if (ACPI_SUCCESS(status) && sta)
|
||||
- return 1;
|
||||
- }
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * eject_device - respond to an eject request
|
||||
- * @handle - the device to eject
|
||||
- *
|
||||
- * Call this devices _EJ0 method.
|
||||
- */
|
||||
-static void eject_device(acpi_handle handle)
|
||||
-{
|
||||
- struct acpi_object_list arg_list;
|
||||
- union acpi_object arg;
|
||||
-
|
||||
- bay_dprintk(handle, "Ejecting device");
|
||||
-
|
||||
- arg_list.count = 1;
|
||||
- arg_list.pointer = &arg;
|
||||
- arg.type = ACPI_TYPE_INTEGER;
|
||||
- arg.integer.value = 1;
|
||||
-
|
||||
- if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
|
||||
- &arg_list, NULL)))
|
||||
- pr_debug("Failed to evaluate _EJ0!\n");
|
||||
-}
|
||||
-
|
||||
-/*
|
||||
- * show_present - read method for "present" file in sysfs
|
||||
- */
|
||||
-static ssize_t show_present(struct device *dev,
|
||||
- struct device_attribute *attr, char *buf)
|
||||
-{
|
||||
- struct bay *bay = dev_get_drvdata(dev);
|
||||
- return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
|
||||
-
|
||||
-}
|
||||
-static DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
|
||||
-
|
||||
-/*
|
||||
- * write_eject - write method for "eject" file in sysfs
|
||||
- */
|
||||
-static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
|
||||
- const char *buf, size_t count)
|
||||
-{
|
||||
- struct bay *bay = dev_get_drvdata(dev);
|
||||
-
|
||||
- if (!count)
|
||||
- return -EINVAL;
|
||||
-
|
||||
- eject_device(bay->handle);
|
||||
- return count;
|
||||
-}
|
||||
-static DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
|
||||
-
|
||||
-/**
|
||||
- * is_ata - see if a device is an ata device
|
||||
- * @handle: acpi handle of the device
|
||||
- *
|
||||
- * If an acpi object has one of 4 ATA ACPI methods defined,
|
||||
- * then it is an ATA device
|
||||
- */
|
||||
-static int is_ata(acpi_handle handle)
|
||||
-{
|
||||
- acpi_handle tmp;
|
||||
-
|
||||
- if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
|
||||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
|
||||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
|
||||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
|
||||
- return 1;
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * parent_is_ata(acpi_handle handle)
|
||||
- *
|
||||
- */
|
||||
-static int parent_is_ata(acpi_handle handle)
|
||||
-{
|
||||
- acpi_handle phandle;
|
||||
-
|
||||
- if (acpi_get_parent(handle, &phandle))
|
||||
- return 0;
|
||||
-
|
||||
- return is_ata(phandle);
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * is_ejectable_bay - see if a device is an ejectable drive bay
|
||||
- * @handle: acpi handle of the device
|
||||
- *
|
||||
- * If an acpi object is ejectable and has one of the ACPI ATA
|
||||
- * methods defined, then we can safely call it an ejectable
|
||||
- * drive bay
|
||||
- */
|
||||
-static int is_ejectable_bay(acpi_handle handle)
|
||||
-{
|
||||
- if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle))
|
||||
- return 1;
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-#if 0
|
||||
-/**
|
||||
- * eject_removable_drive - try to eject this drive
|
||||
- * @dev : the device structure of the drive
|
||||
- *
|
||||
- * If a device is a removable drive that requires an _EJ0 method
|
||||
- * to be executed in order to safely remove from the system, do
|
||||
- * it. ATM - always returns success
|
||||
- */
|
||||
-int eject_removable_drive(struct device *dev)
|
||||
-{
|
||||
- acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
|
||||
-
|
||||
- if (handle) {
|
||||
- bay_dprintk(handle, "Got device handle");
|
||||
- if (is_ejectable_bay(handle))
|
||||
- eject_device(handle);
|
||||
- } else {
|
||||
- printk("No acpi handle for device\n");
|
||||
- }
|
||||
-
|
||||
- /* should I return an error code? */
|
||||
- return 0;
|
||||
-}
|
||||
-EXPORT_SYMBOL_GPL(eject_removable_drive);
|
||||
-#endif /* 0 */
|
||||
-
|
||||
-static int acpi_bay_add_fs(struct bay *bay)
|
||||
-{
|
||||
- int ret;
|
||||
- struct device *dev = &bay->pdev->dev;
|
||||
-
|
||||
- ret = device_create_file(dev, &dev_attr_present);
|
||||
- if (ret)
|
||||
- goto add_fs_err;
|
||||
- ret = device_create_file(dev, &dev_attr_eject);
|
||||
- if (ret) {
|
||||
- device_remove_file(dev, &dev_attr_present);
|
||||
- goto add_fs_err;
|
||||
- }
|
||||
- return 0;
|
||||
-
|
||||
- add_fs_err:
|
||||
- bay_dprintk(bay->handle, "Error adding sysfs files\n");
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static void acpi_bay_remove_fs(struct bay *bay)
|
||||
-{
|
||||
- struct device *dev = &bay->pdev->dev;
|
||||
-
|
||||
- /* cleanup sysfs */
|
||||
- device_remove_file(dev, &dev_attr_present);
|
||||
- device_remove_file(dev, &dev_attr_eject);
|
||||
-}
|
||||
-
|
||||
-static int bay_is_dock_device(acpi_handle handle)
|
||||
-{
|
||||
- acpi_handle parent;
|
||||
-
|
||||
- acpi_get_parent(handle, &parent);
|
||||
-
|
||||
- /* if the device or it's parent is dependent on the
|
||||
- * dock, then we are a dock device
|
||||
- */
|
||||
- return (is_dock_device(handle) || is_dock_device(parent));
|
||||
-}
|
||||
-
|
||||
-static int bay_add(acpi_handle handle, int id)
|
||||
-{
|
||||
- acpi_status status;
|
||||
- struct bay *new_bay;
|
||||
- struct platform_device *pdev;
|
||||
- struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer);
|
||||
-
|
||||
- bay_dprintk(handle, "Adding notify handler");
|
||||
-
|
||||
- /*
|
||||
- * Initialize bay device structure
|
||||
- */
|
||||
- new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC);
|
||||
- INIT_LIST_HEAD(&new_bay->list);
|
||||
- new_bay->handle = handle;
|
||||
- new_bay->name = (char *)nbuffer.pointer;
|
||||
-
|
||||
- /* initialize platform device stuff */
|
||||
- pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0);
|
||||
- if (IS_ERR(pdev)) {
|
||||
- printk(KERN_ERR PREFIX "Error registering bay device\n");
|
||||
- goto bay_add_err;
|
||||
- }
|
||||
- new_bay->pdev = pdev;
|
||||
- platform_set_drvdata(pdev, new_bay);
|
||||
-
|
||||
- /*
|
||||
- * we want the bay driver to be able to send uevents
|
||||
- */
|
||||
- pdev->dev.uevent_suppress = 0;
|
||||
-
|
||||
- /* register for events on this device */
|
||||
- status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
||||
- bay_notify, new_bay);
|
||||
- if (ACPI_FAILURE(status)) {
|
||||
- printk(KERN_INFO PREFIX "Error installing bay notify handler\n");
|
||||
- platform_device_unregister(new_bay->pdev);
|
||||
- goto bay_add_err;
|
||||
- }
|
||||
-
|
||||
- if (acpi_bay_add_fs(new_bay)) {
|
||||
- acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
||||
- bay_notify);
|
||||
- platform_device_unregister(new_bay->pdev);
|
||||
- goto bay_add_err;
|
||||
- }
|
||||
-
|
||||
- /* if we are on a dock station, we should register for dock
|
||||
- * notifications.
|
||||
- */
|
||||
- if (bay_is_dock_device(handle)) {
|
||||
- bay_dprintk(handle, "Is dependent on dock\n");
|
||||
- register_hotplug_dock_device(handle, bay_notify, new_bay);
|
||||
- }
|
||||
- list_add(&new_bay->list, &drive_bays);
|
||||
- printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name);
|
||||
- return 0;
|
||||
-
|
||||
-bay_add_err:
|
||||
- kfree(new_bay->name);
|
||||
- kfree(new_bay);
|
||||
- return -ENODEV;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * bay_notify - act upon an acpi bay notification
|
||||
- * @handle: the bay handle
|
||||
- * @event: the acpi event
|
||||
- * @data: our driver data struct
|
||||
- *
|
||||
- */
|
||||
-static void bay_notify(acpi_handle handle, u32 event, void *data)
|
||||
-{
|
||||
- struct bay *bay_dev = (struct bay *)data;
|
||||
- struct device *dev = &bay_dev->pdev->dev;
|
||||
- char event_string[12];
|
||||
- char *envp[] = { event_string, NULL };
|
||||
-
|
||||
- bay_dprintk(handle, "Bay event");
|
||||
- sprintf(event_string, "BAY_EVENT=%d", event);
|
||||
- kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
-}
|
||||
-
|
||||
-static acpi_status
|
||||
-find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
-{
|
||||
- int *count = (int *)context;
|
||||
-
|
||||
- /*
|
||||
- * there could be more than one ejectable bay.
|
||||
- * so, just return AE_OK always so that every object
|
||||
- * will be checked.
|
||||
- */
|
||||
- if (is_ejectable_bay(handle)) {
|
||||
- bay_dprintk(handle, "found ejectable bay");
|
||||
- if (!bay_add(handle, *count))
|
||||
- (*count)++;
|
||||
- }
|
||||
- return AE_OK;
|
||||
-}
|
||||
-
|
||||
-static int __init bay_init(void)
|
||||
-{
|
||||
- int bays = 0;
|
||||
-
|
||||
- INIT_LIST_HEAD(&drive_bays);
|
||||
-
|
||||
- if (acpi_disabled)
|
||||
- return -ENODEV;
|
||||
-
|
||||
- /* look for dockable drive bays */
|
||||
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
- ACPI_UINT32_MAX, find_bay, &bays, NULL);
|
||||
-
|
||||
- if (!bays)
|
||||
- return -ENODEV;
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static void __exit bay_exit(void)
|
||||
-{
|
||||
- struct bay *bay, *tmp;
|
||||
-
|
||||
- list_for_each_entry_safe(bay, tmp, &drive_bays, list) {
|
||||
- if (is_dock_device(bay->handle))
|
||||
- unregister_hotplug_dock_device(bay->handle);
|
||||
- acpi_bay_remove_fs(bay);
|
||||
- acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY,
|
||||
- bay_notify);
|
||||
- platform_device_unregister(bay->pdev);
|
||||
- kfree(bay->name);
|
||||
- kfree(bay);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-postcore_initcall(bay_init);
|
||||
-module_exit(bay_exit);
|
||||
-
|
||||
@@ -1,164 +0,0 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: Fix duplicate notification handler register
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
Battery driver already registers notification handler. To avoid register
|
||||
notification handler again, the patch introduced a notifier chain in
|
||||
global system notifier handler and use it in dock driver, so we can
|
||||
avoid register notification handler.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
---
|
||||
drivers/acpi/bus.c | 15 +++++++++++++++
|
||||
drivers/acpi/dock.c | 46 ++++++++++++++++++++++++----------------------
|
||||
include/acpi/acpi_bus.h | 3 +++
|
||||
3 files changed, 42 insertions(+), 22 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/bus.c
|
||||
+++ b/drivers/acpi/bus.c
|
||||
@@ -496,6 +496,19 @@ static int acpi_bus_check_scope(struct a
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
|
||||
+int register_acpi_bus_notifier(struct notifier_block *nb)
|
||||
+{
|
||||
+ return blocking_notifier_chain_register(&acpi_bus_notify_list, nb);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(register_acpi_bus_notifier);
|
||||
+
|
||||
+void unregister_acpi_bus_notifier(struct notifier_block *nb)
|
||||
+{
|
||||
+ blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
|
||||
+
|
||||
/**
|
||||
* acpi_bus_notify
|
||||
* ---------------
|
||||
@@ -506,6 +519,8 @@ static void acpi_bus_notify(acpi_handle
|
||||
int result = 0;
|
||||
struct acpi_device *device = NULL;
|
||||
|
||||
+ blocking_notifier_call_chain(&acpi_bus_notify_list,
|
||||
+ type, (void *)handle);
|
||||
|
||||
if (acpi_bus_get_device(handle, &device))
|
||||
return;
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -748,6 +748,28 @@ static void dock_notify(acpi_handle hand
|
||||
}
|
||||
}
|
||||
|
||||
+static int acpi_dock_notifier_call(struct notifier_block *this,
|
||||
+ unsigned long event, void *data)
|
||||
+{
|
||||
+ struct dock_station *dock_station;
|
||||
+ acpi_handle handle = (acpi_handle)data;
|
||||
+
|
||||
+ if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
|
||||
+ && event != ACPI_NOTIFY_EJECT_REQUEST)
|
||||
+ return 0;
|
||||
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
+ if (dock_station->handle == handle) {
|
||||
+ dock_notify(handle, event, dock_station);
|
||||
+ return 0 ;
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct notifier_block dock_acpi_notifier = {
|
||||
+ .notifier_call = acpi_dock_notifier_call,
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* find_dock_devices - find devices on the dock station
|
||||
* @handle: the handle of the device we are examining
|
||||
@@ -859,7 +881,6 @@ static DEVICE_ATTR(uid, S_IRUGO, show_do
|
||||
static int dock_add(acpi_handle handle)
|
||||
{
|
||||
int ret;
|
||||
- acpi_status status;
|
||||
struct dock_dependent_device *dd;
|
||||
struct dock_station *dock_station;
|
||||
struct platform_device *dock_device;
|
||||
@@ -954,23 +975,10 @@ static int dock_add(acpi_handle handle)
|
||||
}
|
||||
add_dock_dependent_device(dock_station, dd);
|
||||
|
||||
- /* register for dock events */
|
||||
- status = acpi_install_notify_handler(dock_station->handle,
|
||||
- ACPI_SYSTEM_NOTIFY,
|
||||
- dock_notify, dock_station);
|
||||
-
|
||||
- if (ACPI_FAILURE(status)) {
|
||||
- printk(KERN_ERR PREFIX "Error installing notify handler\n");
|
||||
- ret = -ENODEV;
|
||||
- goto dock_add_err;
|
||||
- }
|
||||
-
|
||||
dock_station_count++;
|
||||
list_add(&dock_station->sibiling, &dock_stations);
|
||||
return 0;
|
||||
|
||||
-dock_add_err:
|
||||
- kfree(dd);
|
||||
dock_add_err_unregister:
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
@@ -988,7 +996,6 @@ dock_add_err_unregister:
|
||||
static int dock_remove(struct dock_station *dock_station)
|
||||
{
|
||||
struct dock_dependent_device *dd, *tmp;
|
||||
- acpi_status status;
|
||||
struct platform_device *dock_device = dock_station->dock_device;
|
||||
|
||||
if (!dock_station_count)
|
||||
@@ -999,13 +1006,6 @@ static int dock_remove(struct dock_stati
|
||||
list)
|
||||
kfree(dd);
|
||||
|
||||
- /* remove dock notify handler */
|
||||
- status = acpi_remove_notify_handler(dock_station->handle,
|
||||
- ACPI_SYSTEM_NOTIFY,
|
||||
- dock_notify);
|
||||
- if (ACPI_FAILURE(status))
|
||||
- printk(KERN_ERR "Error removing notify handler\n");
|
||||
-
|
||||
/* cleanup sysfs */
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
@@ -1067,6 +1067,7 @@ static int __init dock_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+ register_acpi_bus_notifier(&dock_acpi_notifier);
|
||||
printk(KERN_INFO PREFIX "%s: %d docks/bays found\n",
|
||||
ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
|
||||
return 0;
|
||||
@@ -1076,6 +1077,7 @@ static void __exit dock_exit(void)
|
||||
{
|
||||
struct dock_station *dock_station;
|
||||
|
||||
+ unregister_acpi_bus_notifier(&dock_acpi_notifier);
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling)
|
||||
dock_remove(dock_station);
|
||||
}
|
||||
--- a/include/acpi/acpi_bus.h
|
||||
+++ b/include/acpi/acpi_bus.h
|
||||
@@ -327,6 +327,9 @@ int acpi_bus_get_private_data(acpi_handl
|
||||
extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32);
|
||||
extern int register_acpi_notifier(struct notifier_block *);
|
||||
extern int unregister_acpi_notifier(struct notifier_block *);
|
||||
+
|
||||
+extern int register_acpi_bus_notifier(struct notifier_block *nb);
|
||||
+extern void unregister_acpi_bus_notifier(struct notifier_block *nb);
|
||||
/*
|
||||
* External Functions
|
||||
*/
|
||||
@@ -1,57 +0,0 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: add _LCK support for dock
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
support _LCK method, which is a optional method for hotplug
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
|
||||
index 78d27ce..7bdf93b 100644
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -452,6 +452,25 @@ static inline void complete_undock(struct dock_station *ds)
|
||||
ds->flags &= ~(DOCK_UNDOCKING);
|
||||
}
|
||||
|
||||
+static void dock_lock(struct dock_station *ds, int lock)
|
||||
+{
|
||||
+ struct acpi_object_list arg_list;
|
||||
+ union acpi_object arg;
|
||||
+ acpi_status status;
|
||||
+
|
||||
+ arg_list.count = 1;
|
||||
+ arg_list.pointer = &arg;
|
||||
+ arg.type = ACPI_TYPE_INTEGER;
|
||||
+ arg.integer.value = !!lock;
|
||||
+ status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL);
|
||||
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
+ if (lock)
|
||||
+ printk(KERN_WARNING PREFIX "Locking device failed\n");
|
||||
+ else
|
||||
+ printk(KERN_WARNING PREFIX "Unlocking device failed\n");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* dock_in_progress - see if we are in the middle of handling a dock event
|
||||
* @ds: the dock station
|
||||
@@ -577,6 +596,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
|
||||
|
||||
hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
|
||||
undock(ds);
|
||||
+ dock_lock(ds, 0);
|
||||
eject_dock(ds);
|
||||
if (dock_present(ds)) {
|
||||
printk(KERN_ERR PREFIX "Unable to undock!\n");
|
||||
@@ -617,6 +637,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
|
||||
hotplug_dock_devices(ds, event);
|
||||
complete_dock(ds);
|
||||
dock_event(ds, event, DOCK_EVENT);
|
||||
+ dock_lock(ds, 1);
|
||||
}
|
||||
break;
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
@@ -1,70 +0,0 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: add 'type' sysfs file for dock
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
add a sysfs file to present dock type. Suggested by Holger.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
---
|
||||
drivers/acpi/dock.c | 25 +++++++++++++++++++++++++
|
||||
1 file changed, 25 insertions(+)
|
||||
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -909,6 +909,26 @@ static ssize_t show_dock_uid(struct devi
|
||||
}
|
||||
static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
|
||||
|
||||
+static ssize_t show_dock_type(struct device *dev,
|
||||
+ struct device_attribute *attr, char *buf)
|
||||
+{
|
||||
+ struct dock_station *dock_station = *((struct dock_station **)
|
||||
+ dev->platform_data);
|
||||
+ char *type;
|
||||
+
|
||||
+ if (dock_station->flags & DOCK_IS_DOCK)
|
||||
+ type = "dock_station";
|
||||
+ else if (dock_station->flags & DOCK_IS_ATA)
|
||||
+ type = "ata_bay";
|
||||
+ else if (dock_station->flags & DOCK_IS_BAT)
|
||||
+ type = "battery_bay";
|
||||
+ else
|
||||
+ type = "unknown";
|
||||
+
|
||||
+ return snprintf(buf, PAGE_SIZE, "%s\n", type);
|
||||
+}
|
||||
+static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL);
|
||||
+
|
||||
/**
|
||||
* dock_add - add a new dock station
|
||||
* @handle: the dock station handle
|
||||
@@ -997,6 +1017,9 @@ static int dock_add(acpi_handle handle)
|
||||
dock_station = NULL;
|
||||
return ret;
|
||||
}
|
||||
+ ret = device_create_file(&dock_device->dev, &dev_attr_type);
|
||||
+ if (ret)
|
||||
+ printk(KERN_ERR"Error %d adding sysfs file\n", ret);
|
||||
|
||||
/* Find dependent devices */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
@@ -1018,6 +1041,7 @@ static int dock_add(acpi_handle handle)
|
||||
return 0;
|
||||
|
||||
dock_add_err_unregister:
|
||||
+ device_remove_file(&dock_device->dev, &dev_attr_type);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_uid);
|
||||
@@ -1045,6 +1069,7 @@ static int dock_remove(struct dock_stati
|
||||
kfree(dd);
|
||||
|
||||
/* cleanup sysfs */
|
||||
+ device_remove_file(&dock_device->dev, &dev_attr_type);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_uid);
|
||||
@@ -1,47 +0,0 @@
|
||||
From 1d672ef324e78a467603ef55aa4558cac9f895ba Mon Sep 17 00:00:00 2001
|
||||
From: Holger Macht <hmacht@suse.de>
|
||||
Date: Tue, 20 Jan 2009 12:18:24 +0100
|
||||
Subject: ACPI: dock: Don't eval _STA on every show_docked sysfs read
|
||||
|
||||
From: Holger Macht <hmacht@suse.de>
|
||||
|
||||
commit fc5a9f8841ee87d93376ada5d73117d4d6a373ea upstream.
|
||||
|
||||
Some devices trigger a DEVICE_CHECK on every evalutation of _STA. This
|
||||
can also be seen in commit 8b59560a3baf2e7c24e0fb92ea5d09eca92805db
|
||||
(ACPI: dock: avoid check _STA method). If an undock is processed, the
|
||||
dock driver sends a uevent and userspace might read the show_docked
|
||||
property in sysfs. This causes an evaluation of _STA of the particular
|
||||
device which causes the dock driver to immediately dock again.
|
||||
|
||||
In any case, evaluation of _STA (show_docked) does not necessarily mean
|
||||
that we are docked, so check with the internal device structure.
|
||||
|
||||
http://bugzilla.kernel.org/show_bug.cgi?id=12360
|
||||
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
Signed-off-by: Len Brown <len.brown@intel.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
|
||||
---
|
||||
drivers/acpi/dock.c | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -854,8 +854,14 @@ fdd_out:
|
||||
static ssize_t show_docked(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
- return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
|
||||
+ struct acpi_device *tmp;
|
||||
|
||||
+ struct dock_station *dock_station = *((struct dock_station **)
|
||||
+ dev->platform_data);
|
||||
+
|
||||
+ if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp)))
|
||||
+ return snprintf(buf, PAGE_SIZE, "1\n");
|
||||
+ return snprintf(buf, PAGE_SIZE, "0\n");
|
||||
}
|
||||
static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: fix eject request process
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
commit 2a7feab28d3fc060d320eaba192e49dad1079b7e introduces a bug.
|
||||
My thinkpad actually will send an eject_request and we should follow the
|
||||
eject process to finish the eject, otherwise system still thinks the bay
|
||||
is present.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
|
||||
index 25d2161..78d27ce 100644
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -575,11 +575,6 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
|
||||
*/
|
||||
dock_event(ds, event, UNDOCK_EVENT);
|
||||
|
||||
- if (!dock_present(ds)) {
|
||||
- complete_undock(ds);
|
||||
- return -ENODEV;
|
||||
- }
|
||||
-
|
||||
hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
|
||||
undock(ds);
|
||||
eject_dock(ds);
|
||||
@@ -1,61 +0,0 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: fix for bay in a dock station
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
an ATA bay can be in a dock and itself can be ejected separately. The
|
||||
patch handles such eject bay. Found by Holger.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
---
|
||||
drivers/acpi/dock.c | 14 ++++++++++----
|
||||
1 file changed, 10 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -609,6 +609,7 @@ register_hotplug_dock_device(acpi_handle
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
struct dock_station *dock_station;
|
||||
+ int ret = -EINVAL;
|
||||
|
||||
if (!dock_station_count)
|
||||
return -ENODEV;
|
||||
@@ -618,16 +619,21 @@ register_hotplug_dock_device(acpi_handle
|
||||
* this would include the dock station itself
|
||||
*/
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
+ /*
|
||||
+ * An ATA bay can be in a dock and itself can be ejected
|
||||
+ * seperately, so there are two 'dock stations' which need the
|
||||
+ * ops
|
||||
+ */
|
||||
dd = find_dock_dependent_device(dock_station, handle);
|
||||
if (dd) {
|
||||
dd->ops = ops;
|
||||
dd->context = context;
|
||||
dock_add_hotplug_device(dock_station, dd);
|
||||
- return 0;
|
||||
+ ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
- return -EINVAL;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
|
||||
@@ -1076,8 +1082,8 @@ find_dock(acpi_handle handle, u32 lvl, v
|
||||
static acpi_status
|
||||
find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
- /* If bay is in a dock, it's already handled */
|
||||
- if (is_ejectable_bay(handle) && !is_dock_device(handle))
|
||||
+ /* If bay is a dock, it's already handled */
|
||||
+ if (is_ejectable_bay(handle) && !is_dock(handle))
|
||||
dock_add(handle);
|
||||
return AE_OK;
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: fix hotplug race
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
hotplug notification handler and drivers' notification handler are all
|
||||
running in one workqueue. Before hotplug removes an acpi device, the
|
||||
device driver's notification handler is already be recorded to run just
|
||||
after global notification handler. After hotplug notification handler
|
||||
runs, acpica will notice a NULL notification handler and crash. This
|
||||
patch runs hotplug in other workqueue and wait for all acpi notication
|
||||
handlers finish. This is found in battery hotplug, but actually all
|
||||
hotplug can be affected.
|
||||
|
||||
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
---
|
||||
drivers/acpi/dock.c | 25 ++++++++++++++++++++++++-
|
||||
drivers/acpi/osl.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
|
||||
include/acpi/acpiosxf.h | 3 +++
|
||||
3 files changed, 68 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -748,6 +748,20 @@ static void dock_notify(acpi_handle hand
|
||||
}
|
||||
}
|
||||
|
||||
+struct dock_data {
|
||||
+ acpi_handle handle;
|
||||
+ unsigned long event;
|
||||
+ struct dock_station *ds;
|
||||
+};
|
||||
+
|
||||
+static void acpi_dock_deferred_cb(void *context)
|
||||
+{
|
||||
+ struct dock_data *data = (struct dock_data *)context;
|
||||
+
|
||||
+ dock_notify(data->handle, data->event, data->ds);
|
||||
+ kfree(data);
|
||||
+}
|
||||
+
|
||||
static int acpi_dock_notifier_call(struct notifier_block *this,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
@@ -759,7 +773,16 @@ static int acpi_dock_notifier_call(struc
|
||||
return 0;
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
if (dock_station->handle == handle) {
|
||||
- dock_notify(handle, event, dock_station);
|
||||
+ struct dock_data *dock_data;
|
||||
+
|
||||
+ dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL);
|
||||
+ if (!dock_data)
|
||||
+ return 0;
|
||||
+ dock_data->handle = handle;
|
||||
+ dock_data->event = event;
|
||||
+ dock_data->ds = dock_station;
|
||||
+ acpi_os_hotplug_execute(acpi_dock_deferred_cb,
|
||||
+ dock_data);
|
||||
return 0 ;
|
||||
}
|
||||
}
|
||||
--- a/drivers/acpi/osl.c
|
||||
+++ b/drivers/acpi/osl.c
|
||||
@@ -705,6 +705,22 @@ static void acpi_os_execute_deferred(str
|
||||
return;
|
||||
}
|
||||
|
||||
+static void acpi_os_execute_hp_deferred(struct work_struct *work)
|
||||
+{
|
||||
+ struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
|
||||
+ if (!dpc) {
|
||||
+ printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ acpi_os_wait_events_complete(NULL);
|
||||
+
|
||||
+ dpc->function(dpc->context);
|
||||
+ kfree(dpc);
|
||||
+
|
||||
+ return;
|
||||
+}
|
||||
+
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_os_execute
|
||||
@@ -720,12 +736,13 @@ static void acpi_os_execute_deferred(str
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
-acpi_status acpi_os_execute(acpi_execute_type type,
|
||||
- acpi_osd_exec_callback function, void *context)
|
||||
+static acpi_status __acpi_os_execute(acpi_execute_type type,
|
||||
+ acpi_osd_exec_callback function, void *context, int hp)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_os_dpc *dpc;
|
||||
struct workqueue_struct *queue;
|
||||
+ int ret;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Scheduling function [%p(%p)] for deferred execution.\n",
|
||||
function, context));
|
||||
@@ -749,9 +766,17 @@ acpi_status acpi_os_execute(acpi_execute
|
||||
dpc->function = function;
|
||||
dpc->context = context;
|
||||
|
||||
- INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
||||
- queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
|
||||
- if (!queue_work(queue, &dpc->work)) {
|
||||
+ if (!hp) {
|
||||
+ INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
||||
+ queue = (type == OSL_NOTIFY_HANDLER) ?
|
||||
+ kacpi_notify_wq : kacpid_wq;
|
||||
+ ret = queue_work(queue, &dpc->work);
|
||||
+ } else {
|
||||
+ INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred);
|
||||
+ ret = schedule_work(&dpc->work);
|
||||
+ }
|
||||
+
|
||||
+ if (!ret) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Call to queue_work() failed.\n"));
|
||||
status = AE_ERROR;
|
||||
@@ -760,8 +785,19 @@ acpi_status acpi_os_execute(acpi_execute
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
+acpi_status acpi_os_execute(acpi_execute_type type,
|
||||
+ acpi_osd_exec_callback function, void *context)
|
||||
+{
|
||||
+ return __acpi_os_execute(type, function, context, 0);
|
||||
+}
|
||||
EXPORT_SYMBOL(acpi_os_execute);
|
||||
|
||||
+acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
|
||||
+ void *context)
|
||||
+{
|
||||
+ return __acpi_os_execute(0, function, context, 1);
|
||||
+}
|
||||
+
|
||||
void acpi_os_wait_events_complete(void *context)
|
||||
{
|
||||
flush_workqueue(kacpid_wq);
|
||||
--- a/include/acpi/acpiosxf.h
|
||||
+++ b/include/acpi/acpiosxf.h
|
||||
@@ -193,6 +193,9 @@ acpi_status
|
||||
acpi_os_execute(acpi_execute_type type,
|
||||
acpi_osd_exec_callback function, void *context);
|
||||
|
||||
+acpi_status
|
||||
+acpi_os_hotplug_execute(acpi_osd_exec_callback function, void *context);
|
||||
+
|
||||
void acpi_os_wait_events_complete(void *context);
|
||||
|
||||
void acpi_os_sleep(acpi_integer milliseconds);
|
||||
@@ -1,214 +0,0 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: introduce .uevent for devices in dock
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
dock's uevent reported itself, not ata. It might be difficult to find an
|
||||
ata device just according to a dock. This patch introduces docking ops
|
||||
for each device in a dock. when docking, dock driver can send device
|
||||
specific uevent. This should help dock station too (not just bay)
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
|
||||
index f19f643..ac7dfef 100644
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -75,7 +75,7 @@ struct dock_dependent_device {
|
||||
struct list_head list;
|
||||
struct list_head hotplug_list;
|
||||
acpi_handle handle;
|
||||
- acpi_notify_handler handler;
|
||||
+ struct acpi_dock_ops *ops;
|
||||
void *context;
|
||||
};
|
||||
|
||||
@@ -385,8 +385,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
|
||||
* First call driver specific hotplug functions
|
||||
*/
|
||||
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
|
||||
- if (dd->handler)
|
||||
- dd->handler(dd->handle, event, dd->context);
|
||||
+ if (dd->ops && dd->ops->handler)
|
||||
+ dd->ops->handler(dd->handle, event, dd->context);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -409,6 +409,7 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
|
||||
struct device *dev = &ds->dock_device->dev;
|
||||
char event_string[13];
|
||||
char *envp[] = { event_string, NULL };
|
||||
+ struct dock_dependent_device *dd;
|
||||
|
||||
if (num == UNDOCK_EVENT)
|
||||
sprintf(event_string, "EVENT=undock");
|
||||
@@ -419,7 +420,14 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
|
||||
* Indicate that the status of the dock station has
|
||||
* changed.
|
||||
*/
|
||||
- kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
+ if (num == DOCK_EVENT)
|
||||
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
+
|
||||
+ list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
|
||||
+ if (dd->ops && dd->ops->uevent)
|
||||
+ dd->ops->uevent(dd->handle, event, dd->context);
|
||||
+ if (num != DOCK_EVENT)
|
||||
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -588,7 +596,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
|
||||
/**
|
||||
* register_hotplug_dock_device - register a hotplug function
|
||||
* @handle: the handle of the device
|
||||
- * @handler: the acpi_notifier_handler to call after docking
|
||||
+ * @ops: handlers to call after docking
|
||||
* @context: device specific data
|
||||
*
|
||||
* If a driver would like to perform a hotplug operation after a dock
|
||||
@@ -596,7 +604,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
|
||||
* the dock driver after _DCK is executed.
|
||||
*/
|
||||
int
|
||||
-register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
|
||||
+register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops,
|
||||
void *context)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
@@ -612,7 +620,7 @@ register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
dd = find_dock_dependent_device(dock_station, handle);
|
||||
if (dd) {
|
||||
- dd->handler = handler;
|
||||
+ dd->ops = ops;
|
||||
dd->context = context;
|
||||
dock_add_hotplug_device(dock_station, dd);
|
||||
return 0;
|
||||
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
|
||||
index 97727be..c012307 100644
|
||||
--- a/drivers/ata/libata-acpi.c
|
||||
+++ b/drivers/ata/libata-acpi.c
|
||||
@@ -209,6 +209,46 @@ static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
|
||||
ata_acpi_handle_hotplug(ap, NULL, event);
|
||||
}
|
||||
|
||||
+static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
|
||||
+ u32 event)
|
||||
+{
|
||||
+ struct kobject *kobj = NULL;
|
||||
+ char event_string[20];
|
||||
+ char *envp[] = { event_string, NULL };
|
||||
+
|
||||
+ if (dev) {
|
||||
+ if (dev->sdev)
|
||||
+ kobj = &dev->sdev->sdev_gendev.kobj;
|
||||
+ } else
|
||||
+ kobj = &ap->dev->kobj;
|
||||
+
|
||||
+ if (kobj) {
|
||||
+ snprintf(event_string, 20, "BAY_EVENT=%d", event);
|
||||
+ kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
|
||||
+{
|
||||
+ ata_acpi_uevent(data, NULL, event);
|
||||
+}
|
||||
+
|
||||
+static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
|
||||
+{
|
||||
+ struct ata_device *dev = data;
|
||||
+ ata_acpi_uevent(dev->link->ap, dev, event);
|
||||
+}
|
||||
+
|
||||
+static struct acpi_dock_ops ata_acpi_dev_dock_ops = {
|
||||
+ .handler = ata_acpi_dev_notify_dock,
|
||||
+ .uevent = ata_acpi_dev_uevent,
|
||||
+};
|
||||
+
|
||||
+static struct acpi_dock_ops ata_acpi_ap_dock_ops = {
|
||||
+ .handler = ata_acpi_ap_notify_dock,
|
||||
+ .uevent = ata_acpi_ap_uevent,
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* ata_acpi_associate - associate ATA host with ACPI objects
|
||||
* @host: target ATA host
|
||||
@@ -244,7 +284,7 @@ void ata_acpi_associate(struct ata_host *host)
|
||||
if (ap->acpi_handle) {
|
||||
/* we might be on a docking station */
|
||||
register_hotplug_dock_device(ap->acpi_handle,
|
||||
- ata_acpi_ap_notify_dock, ap);
|
||||
+ &ata_acpi_ap_dock_ops, ap);
|
||||
}
|
||||
|
||||
for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
|
||||
@@ -253,7 +293,7 @@ void ata_acpi_associate(struct ata_host *host)
|
||||
if (dev->acpi_handle) {
|
||||
/* we might be on a docking station */
|
||||
register_hotplug_dock_device(dev->acpi_handle,
|
||||
- ata_acpi_dev_notify_dock, dev);
|
||||
+ &ata_acpi_dev_dock_ops, dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
|
||||
index a3e4705..db54c5e 100644
|
||||
--- a/drivers/pci/hotplug/acpiphp_glue.c
|
||||
+++ b/drivers/pci/hotplug/acpiphp_glue.c
|
||||
@@ -169,7 +169,9 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
|
||||
}
|
||||
|
||||
|
||||
-
|
||||
+static struct acpi_dock_ops acpiphp_dock_ops = {
|
||||
+ .handler = handle_hotplug_event_func,
|
||||
+};
|
||||
|
||||
/* callback routine to register each ACPI PCI slot object */
|
||||
static acpi_status
|
||||
@@ -285,7 +287,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
*/
|
||||
newfunc->flags &= ~FUNC_HAS_EJ0;
|
||||
if (register_hotplug_dock_device(handle,
|
||||
- handle_hotplug_event_func, newfunc))
|
||||
+ &acpiphp_dock_ops, newfunc))
|
||||
dbg("failed to register dock device\n");
|
||||
|
||||
/* we need to be notified when dock events happen
|
||||
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
|
||||
index e5f38e5..4f5042a 100644
|
||||
--- a/include/acpi/acpi_drivers.h
|
||||
+++ b/include/acpi/acpi_drivers.h
|
||||
@@ -115,12 +115,17 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type);
|
||||
/*--------------------------------------------------------------------------
|
||||
Dock Station
|
||||
-------------------------------------------------------------------------- */
|
||||
+struct acpi_dock_ops {
|
||||
+ acpi_notify_handler handler;
|
||||
+ acpi_notify_handler uevent;
|
||||
+};
|
||||
+
|
||||
#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
|
||||
extern int is_dock_device(acpi_handle handle);
|
||||
extern int register_dock_notifier(struct notifier_block *nb);
|
||||
extern void unregister_dock_notifier(struct notifier_block *nb);
|
||||
extern int register_hotplug_dock_device(acpi_handle handle,
|
||||
- acpi_notify_handler handler,
|
||||
+ struct acpi_dock_ops *ops,
|
||||
void *context);
|
||||
extern void unregister_hotplug_dock_device(acpi_handle handle);
|
||||
#else
|
||||
@@ -136,7 +141,7 @@ static inline void unregister_dock_notifier(struct notifier_block *nb)
|
||||
{
|
||||
}
|
||||
static inline int register_hotplug_dock_device(acpi_handle handle,
|
||||
- acpi_notify_handler handler,
|
||||
+ struct acpi_dock_ops *ops,
|
||||
void *context)
|
||||
{
|
||||
return -ENODEV;
|
||||
@@ -1,451 +0,0 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: makeing dock driver supports bay and battery hotplug
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
Making dock driver supports bay and battery hotplug. They are all
|
||||
regarded as dock, and unified handled.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
---
|
||||
drivers/acpi/dock.c | 221 ++++++++++++++++++++++++++++++++++++++++------------
|
||||
1 file changed, 173 insertions(+), 48 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -48,7 +48,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (d
|
||||
" before undocking");
|
||||
|
||||
static struct atomic_notifier_head dock_notifier_list;
|
||||
-static struct platform_device *dock_device;
|
||||
static char dock_device_name[] = "dock";
|
||||
|
||||
static const struct acpi_device_id dock_device_ids[] = {
|
||||
@@ -65,7 +64,12 @@ struct dock_station {
|
||||
struct mutex hp_lock;
|
||||
struct list_head dependent_devices;
|
||||
struct list_head hotplug_devices;
|
||||
+
|
||||
+ struct list_head sibiling;
|
||||
+ struct platform_device *dock_device;
|
||||
};
|
||||
+static LIST_HEAD(dock_stations);
|
||||
+static int dock_station_count;
|
||||
|
||||
struct dock_dependent_device {
|
||||
struct list_head list;
|
||||
@@ -77,11 +81,12 @@ struct dock_dependent_device {
|
||||
|
||||
#define DOCK_DOCKING 0x00000001
|
||||
#define DOCK_UNDOCKING 0x00000002
|
||||
+#define DOCK_IS_DOCK 0x00000010
|
||||
+#define DOCK_IS_ATA 0x00000020
|
||||
+#define DOCK_IS_BAT 0x00000040
|
||||
#define DOCK_EVENT 3
|
||||
#define UNDOCK_EVENT 2
|
||||
|
||||
-static struct dock_station *dock_station;
|
||||
-
|
||||
/*****************************************************************************
|
||||
* Dock Dependent device functions *
|
||||
*****************************************************************************/
|
||||
@@ -199,6 +204,60 @@ static int is_dock(acpi_handle handle)
|
||||
return 1;
|
||||
}
|
||||
|
||||
+static int is_ejectable(acpi_handle handle)
|
||||
+{
|
||||
+ acpi_status status;
|
||||
+ acpi_handle tmp;
|
||||
+
|
||||
+ status = acpi_get_handle(handle, "_EJ0", &tmp);
|
||||
+ if (ACPI_FAILURE(status))
|
||||
+ return 0;
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static int is_ata(acpi_handle handle)
|
||||
+{
|
||||
+ acpi_handle tmp;
|
||||
+
|
||||
+ if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
|
||||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
|
||||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
|
||||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
|
||||
+ return 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int is_battery(acpi_handle handle)
|
||||
+{
|
||||
+ struct acpi_device_info *info;
|
||||
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
+ int ret = 1;
|
||||
+
|
||||
+ if (!ACPI_SUCCESS(acpi_get_object_info(handle, &buffer)))
|
||||
+ return 0;
|
||||
+ info = buffer.pointer;
|
||||
+ if (!(info->valid & ACPI_VALID_HID))
|
||||
+ ret = 0;
|
||||
+ else
|
||||
+ ret = !strcmp("PNP0C0A", info->hardware_id.value);
|
||||
+
|
||||
+ kfree(buffer.pointer);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int is_ejectable_bay(acpi_handle handle)
|
||||
+{
|
||||
+ acpi_handle phandle;
|
||||
+ if (!is_ejectable(handle))
|
||||
+ return 0;
|
||||
+ if (is_battery(handle) || is_ata(handle))
|
||||
+ return 1;
|
||||
+ if (!acpi_get_parent(handle, &phandle) && is_ata(phandle))
|
||||
+ return 1;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* is_dock_device - see if a device is on a dock station
|
||||
* @handle: acpi handle of the device
|
||||
@@ -209,11 +268,17 @@ static int is_dock(acpi_handle handle)
|
||||
*/
|
||||
int is_dock_device(acpi_handle handle)
|
||||
{
|
||||
- if (!dock_station)
|
||||
+ struct dock_station *dock_station;
|
||||
+
|
||||
+ if (!dock_station_count)
|
||||
return 0;
|
||||
|
||||
- if (is_dock(handle) || find_dock_dependent_device(dock_station, handle))
|
||||
+ if (is_dock(handle))
|
||||
return 1;
|
||||
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
+ if (find_dock_dependent_device(dock_station, handle))
|
||||
+ return 1;
|
||||
+ }
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -341,7 +406,7 @@ static void hotplug_dock_devices(struct
|
||||
|
||||
static void dock_event(struct dock_station *ds, u32 event, int num)
|
||||
{
|
||||
- struct device *dev = &dock_device->dev;
|
||||
+ struct device *dev = &ds->dock_device->dev;
|
||||
char event_string[13];
|
||||
char *envp[] = { event_string, NULL };
|
||||
|
||||
@@ -414,7 +479,7 @@ static void handle_dock(struct dock_stat
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
arg.integer.value = dock;
|
||||
status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
|
||||
- if (ACPI_FAILURE(status))
|
||||
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
|
||||
printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
|
||||
(char *)name_buffer.pointer);
|
||||
kfree(buffer.pointer);
|
||||
@@ -498,7 +563,7 @@ static int dock_in_progress(struct dock_
|
||||
*/
|
||||
int register_dock_notifier(struct notifier_block *nb)
|
||||
{
|
||||
- if (!dock_station)
|
||||
+ if (!dock_station_count)
|
||||
return -ENODEV;
|
||||
|
||||
return atomic_notifier_chain_register(&dock_notifier_list, nb);
|
||||
@@ -512,7 +577,7 @@ EXPORT_SYMBOL_GPL(register_dock_notifier
|
||||
*/
|
||||
void unregister_dock_notifier(struct notifier_block *nb)
|
||||
{
|
||||
- if (!dock_station)
|
||||
+ if (!dock_station_count)
|
||||
return;
|
||||
|
||||
atomic_notifier_chain_unregister(&dock_notifier_list, nb);
|
||||
@@ -535,20 +600,23 @@ register_hotplug_dock_device(acpi_handle
|
||||
void *context)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
+ struct dock_station *dock_station;
|
||||
|
||||
- if (!dock_station)
|
||||
+ if (!dock_station_count)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* make sure this handle is for a device dependent on the dock,
|
||||
* this would include the dock station itself
|
||||
*/
|
||||
- dd = find_dock_dependent_device(dock_station, handle);
|
||||
- if (dd) {
|
||||
- dd->handler = handler;
|
||||
- dd->context = context;
|
||||
- dock_add_hotplug_device(dock_station, dd);
|
||||
- return 0;
|
||||
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
+ dd = find_dock_dependent_device(dock_station, handle);
|
||||
+ if (dd) {
|
||||
+ dd->handler = handler;
|
||||
+ dd->context = context;
|
||||
+ dock_add_hotplug_device(dock_station, dd);
|
||||
+ return 0;
|
||||
+ }
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
@@ -563,13 +631,16 @@ EXPORT_SYMBOL_GPL(register_hotplug_dock_
|
||||
void unregister_hotplug_dock_device(acpi_handle handle)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
+ struct dock_station *dock_station;
|
||||
|
||||
- if (!dock_station)
|
||||
+ if (!dock_station_count)
|
||||
return;
|
||||
|
||||
- dd = find_dock_dependent_device(dock_station, handle);
|
||||
- if (dd)
|
||||
- dock_del_hotplug_device(dock_station, dd);
|
||||
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
+ dd = find_dock_dependent_device(dock_station, handle);
|
||||
+ if (dd)
|
||||
+ dock_del_hotplug_device(dock_station, dd);
|
||||
+ }
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
|
||||
@@ -620,9 +691,28 @@ static void dock_notify(acpi_handle hand
|
||||
{
|
||||
struct dock_station *ds = data;
|
||||
struct acpi_device *tmp;
|
||||
+ int surprise_removal = 0;
|
||||
|
||||
+ /*
|
||||
+ * According to acpi spec 3.0a, if a DEVICE_CHECK notification
|
||||
+ * is sent and _DCK is present, it is assumed to mean an undock
|
||||
+ * request.
|
||||
+ */
|
||||
+ if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
|
||||
+ event = ACPI_NOTIFY_EJECT_REQUEST;
|
||||
+
|
||||
+ /*
|
||||
+ * dock station: BUS_CHECK - docked or surprise removal
|
||||
+ * DEVICE_CHECK - undocked
|
||||
+ * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal
|
||||
+ *
|
||||
+ * To simplify event handling, dock dependent device handler always
|
||||
+ * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
|
||||
+ * ACPI_NOTIFY_EJECT_REQUEST for removal
|
||||
+ */
|
||||
switch (event) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
+ case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
|
||||
&tmp)) {
|
||||
begin_dock(ds);
|
||||
@@ -638,20 +728,17 @@ static void dock_notify(acpi_handle hand
|
||||
complete_dock(ds);
|
||||
dock_event(ds, event, DOCK_EVENT);
|
||||
dock_lock(ds, 1);
|
||||
+ break;
|
||||
}
|
||||
- break;
|
||||
- case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
- /*
|
||||
- * According to acpi spec 3.0a, if a DEVICE_CHECK notification
|
||||
- * is sent and _DCK is present, it is assumed to mean an
|
||||
- * undock request. This notify routine will only be called
|
||||
- * for objects defining _DCK, so we will fall through to eject
|
||||
- * request here. However, we will pass an eject request through
|
||||
- * to the driver who wish to hotplug.
|
||||
- */
|
||||
+ if (dock_present(ds) || dock_in_progress(ds))
|
||||
+ break;
|
||||
+ /* This is a surprise removal */
|
||||
+ surprise_removal = 1;
|
||||
+ event = ACPI_NOTIFY_EJECT_REQUEST;
|
||||
+ /* Fall back */
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
begin_undock(ds);
|
||||
- if (immediate_undock)
|
||||
+ if (immediate_undock || surprise_removal)
|
||||
handle_eject_request(ds, event);
|
||||
else
|
||||
dock_event(ds, event, UNDOCK_EVENT);
|
||||
@@ -718,6 +805,8 @@ static DEVICE_ATTR(docked, S_IRUGO, show
|
||||
static ssize_t show_flags(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
+ struct dock_station *dock_station = *((struct dock_station **)
|
||||
+ dev->platform_data);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
|
||||
|
||||
}
|
||||
@@ -730,6 +819,8 @@ static ssize_t write_undock(struct devic
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
+ struct dock_station *dock_station = *((struct dock_station **)
|
||||
+ dev->platform_data);
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
@@ -747,6 +838,8 @@ static ssize_t show_dock_uid(struct devi
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
unsigned long long lbuf;
|
||||
+ struct dock_station *dock_station = *((struct dock_station **)
|
||||
+ dev->platform_data);
|
||||
acpi_status status = acpi_evaluate_integer(dock_station->handle,
|
||||
"_UID", NULL, &lbuf);
|
||||
if (ACPI_FAILURE(status))
|
||||
@@ -768,6 +861,8 @@ static int dock_add(acpi_handle handle)
|
||||
int ret;
|
||||
acpi_status status;
|
||||
struct dock_dependent_device *dd;
|
||||
+ struct dock_station *dock_station;
|
||||
+ struct platform_device *dock_device;
|
||||
|
||||
/* allocate & initialize the dock_station private data */
|
||||
dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
|
||||
@@ -777,22 +872,34 @@ static int dock_add(acpi_handle handle)
|
||||
dock_station->last_dock_time = jiffies - HZ;
|
||||
INIT_LIST_HEAD(&dock_station->dependent_devices);
|
||||
INIT_LIST_HEAD(&dock_station->hotplug_devices);
|
||||
+ INIT_LIST_HEAD(&dock_station->sibiling);
|
||||
spin_lock_init(&dock_station->dd_lock);
|
||||
mutex_init(&dock_station->hp_lock);
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
|
||||
|
||||
/* initialize platform device stuff */
|
||||
- dock_device =
|
||||
- platform_device_register_simple(dock_device_name, 0, NULL, 0);
|
||||
+ dock_station->dock_device =
|
||||
+ platform_device_register_simple(dock_device_name,
|
||||
+ dock_station_count, NULL, 0);
|
||||
+ dock_device = dock_station->dock_device;
|
||||
if (IS_ERR(dock_device)) {
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return PTR_ERR(dock_device);
|
||||
}
|
||||
+ platform_device_add_data(dock_device, &dock_station,
|
||||
+ sizeof(struct dock_station *));
|
||||
|
||||
/* we want the dock device to send uevents */
|
||||
dock_device->dev.uevent_suppress = 0;
|
||||
|
||||
+ if (is_dock(handle))
|
||||
+ dock_station->flags |= DOCK_IS_DOCK;
|
||||
+ if (is_ata(handle))
|
||||
+ dock_station->flags |= DOCK_IS_ATA;
|
||||
+ if (is_battery(handle))
|
||||
+ dock_station->flags |= DOCK_IS_BAT;
|
||||
+
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_docked);
|
||||
if (ret) {
|
||||
printk("Error %d adding sysfs file\n", ret);
|
||||
@@ -858,8 +965,8 @@ static int dock_add(acpi_handle handle)
|
||||
goto dock_add_err;
|
||||
}
|
||||
|
||||
- printk(KERN_INFO PREFIX "%s\n", ACPI_DOCK_DRIVER_DESCRIPTION);
|
||||
-
|
||||
+ dock_station_count++;
|
||||
+ list_add(&dock_station->sibiling, &dock_stations);
|
||||
return 0;
|
||||
|
||||
dock_add_err:
|
||||
@@ -878,12 +985,13 @@ dock_add_err_unregister:
|
||||
/**
|
||||
* dock_remove - free up resources related to the dock station
|
||||
*/
|
||||
-static int dock_remove(void)
|
||||
+static int dock_remove(struct dock_station *dock_station)
|
||||
{
|
||||
struct dock_dependent_device *dd, *tmp;
|
||||
acpi_status status;
|
||||
+ struct platform_device *dock_device = dock_station->dock_device;
|
||||
|
||||
- if (!dock_station)
|
||||
+ if (!dock_station_count)
|
||||
return 0;
|
||||
|
||||
/* remove dependent devices */
|
||||
@@ -923,41 +1031,58 @@ static int dock_remove(void)
|
||||
static acpi_status
|
||||
find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
- int *count = context;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
if (is_dock(handle)) {
|
||||
if (dock_add(handle) >= 0) {
|
||||
- (*count)++;
|
||||
status = AE_CTRL_TERMINATE;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
-static int __init dock_init(void)
|
||||
+static acpi_status
|
||||
+find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
- int num = 0;
|
||||
-
|
||||
- dock_station = NULL;
|
||||
+ /* If bay is in a dock, it's already handled */
|
||||
+ if (is_ejectable_bay(handle) && !is_dock_device(handle))
|
||||
+ dock_add(handle);
|
||||
+ return AE_OK;
|
||||
+}
|
||||
|
||||
+static int __init dock_init(void)
|
||||
+{
|
||||
if (acpi_disabled)
|
||||
return 0;
|
||||
|
||||
/* look for a dock station */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
- ACPI_UINT32_MAX, find_dock, &num, NULL);
|
||||
+ ACPI_UINT32_MAX, find_dock, NULL, NULL);
|
||||
|
||||
- if (!num)
|
||||
- printk(KERN_INFO "No dock devices found.\n");
|
||||
+ /* look for bay */
|
||||
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
+ ACPI_UINT32_MAX, find_bay, NULL, NULL);
|
||||
+ if (!dock_station_count) {
|
||||
+ printk(KERN_INFO PREFIX "No dock devices found.\n");
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
+ printk(KERN_INFO PREFIX "%s: %d docks/bays found\n",
|
||||
+ ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dock_exit(void)
|
||||
{
|
||||
- dock_remove();
|
||||
+ struct dock_station *dock_station;
|
||||
+
|
||||
+ list_for_each_entry(dock_station, &dock_stations, sibiling)
|
||||
+ dock_remove(dock_station);
|
||||
}
|
||||
|
||||
-postcore_initcall(dock_init);
|
||||
+/*
|
||||
+ * Must be called before drivers of devices in dock, otherwise we can't know
|
||||
+ * which devices are in a dock
|
||||
+ */
|
||||
+subsys_initcall(dock_init);
|
||||
module_exit(dock_exit);
|
||||
@@ -1,23 +0,0 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: acpi: export acpi_os_hotplug_execute
|
||||
|
||||
The ACPI dock driver changes require acpi_os_hotplug_execute,
|
||||
which wasn't exported.
|
||||
|
||||
This patch exports it.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
drivers/acpi/osl.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/acpi/osl.c
|
||||
+++ b/drivers/acpi/osl.c
|
||||
@@ -797,6 +797,7 @@ acpi_status acpi_os_hotplug_execute(acpi
|
||||
{
|
||||
return __acpi_os_execute(0, function, context, 1);
|
||||
}
|
||||
+EXPORT_SYMBOL(acpi_os_hotplug_execute);
|
||||
|
||||
void acpi_os_wait_events_complete(void *context)
|
||||
{
|
||||
@@ -1,211 +0,0 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: libata hotplug to align with dock driver
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
dock driver can handle ata(bay) hotplug now. dock driver already handles
|
||||
_EJ0 and _STA, so remove them. Also libata doesn't need register
|
||||
notification handler anymore.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
|
||||
index 4b395b1..f19f643 100644
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -738,7 +738,8 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
|
||||
/* Fall back */
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
begin_undock(ds);
|
||||
- if (immediate_undock || surprise_removal)
|
||||
+ if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
|
||||
+ || surprise_removal)
|
||||
handle_eject_request(ds, event);
|
||||
else
|
||||
dock_event(ds, event, UNDOCK_EVENT);
|
||||
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
|
||||
index 9330b79..97727be 100644
|
||||
--- a/drivers/ata/libata-acpi.c
|
||||
+++ b/drivers/ata/libata-acpi.c
|
||||
@@ -120,21 +120,6 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
|
||||
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
|
||||
}
|
||||
|
||||
-static void ata_acpi_eject_device(acpi_handle handle)
|
||||
-{
|
||||
- struct acpi_object_list arg_list;
|
||||
- union acpi_object arg;
|
||||
-
|
||||
- arg_list.count = 1;
|
||||
- arg_list.pointer = &arg;
|
||||
- arg.type = ACPI_TYPE_INTEGER;
|
||||
- arg.integer.value = 1;
|
||||
-
|
||||
- if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
|
||||
- &arg_list, NULL)))
|
||||
- printk(KERN_ERR "Failed to evaluate _EJ0!\n");
|
||||
-}
|
||||
-
|
||||
/* @ap and @dev are the same as ata_acpi_handle_hotplug() */
|
||||
static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
|
||||
{
|
||||
@@ -157,7 +142,6 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
|
||||
* @ap: ATA port ACPI event occurred
|
||||
* @dev: ATA device ACPI event occurred (can be NULL)
|
||||
* @event: ACPI event which occurred
|
||||
- * @is_dock_event: boolean indicating whether the event was a dock one
|
||||
*
|
||||
* All ACPI bay / device realted events end up in this function. If
|
||||
* the event is port-wide @dev is NULL. If the event is specific to a
|
||||
@@ -171,115 +155,58 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
|
||||
* ACPI notify handler context. May sleep.
|
||||
*/
|
||||
static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
|
||||
- u32 event, int is_dock_event)
|
||||
+ u32 event)
|
||||
{
|
||||
- char event_string[12];
|
||||
- char *envp[] = { event_string, NULL };
|
||||
struct ata_eh_info *ehi = &ap->link.eh_info;
|
||||
- struct kobject *kobj = NULL;
|
||||
int wait = 0;
|
||||
unsigned long flags;
|
||||
- acpi_handle handle, tmphandle;
|
||||
- unsigned long long sta;
|
||||
- acpi_status status;
|
||||
+ acpi_handle handle;
|
||||
|
||||
- if (dev) {
|
||||
- if (dev->sdev)
|
||||
- kobj = &dev->sdev->sdev_gendev.kobj;
|
||||
+ if (dev)
|
||||
handle = dev->acpi_handle;
|
||||
- } else {
|
||||
- kobj = &ap->dev->kobj;
|
||||
+ else
|
||||
handle = ap->acpi_handle;
|
||||
- }
|
||||
-
|
||||
- status = acpi_get_handle(handle, "_EJ0", &tmphandle);
|
||||
- if (ACPI_FAILURE(status))
|
||||
- /* This device does not support hotplug */
|
||||
- return;
|
||||
-
|
||||
- if (event == ACPI_NOTIFY_BUS_CHECK ||
|
||||
- event == ACPI_NOTIFY_DEVICE_CHECK)
|
||||
- status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
-
|
||||
+ /*
|
||||
+ * When dock driver calls into the routine, it will always use
|
||||
+ * ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
|
||||
+ * ACPI_NOTIFY_EJECT_REQUEST for remove
|
||||
+ */
|
||||
switch (event) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
ata_ehi_push_desc(ehi, "ACPI event");
|
||||
|
||||
- if (ACPI_FAILURE(status)) {
|
||||
- ata_port_printk(ap, KERN_ERR,
|
||||
- "acpi: failed to determine bay status (0x%x)\n",
|
||||
- status);
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- if (sta) {
|
||||
- ata_ehi_hotplugged(ehi);
|
||||
- ata_port_freeze(ap);
|
||||
- } else {
|
||||
- /* The device has gone - unplug it */
|
||||
- ata_acpi_detach_device(ap, dev);
|
||||
- wait = 1;
|
||||
- }
|
||||
+ ata_ehi_hotplugged(ehi);
|
||||
+ ata_port_freeze(ap);
|
||||
break;
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
ata_ehi_push_desc(ehi, "ACPI event");
|
||||
|
||||
- if (!is_dock_event)
|
||||
- break;
|
||||
-
|
||||
- /* undock event - immediate unplug */
|
||||
ata_acpi_detach_device(ap, dev);
|
||||
wait = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
- /* make sure kobj doesn't go away while ap->lock is released */
|
||||
- kobject_get(kobj);
|
||||
-
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
- if (wait) {
|
||||
+ if (wait)
|
||||
ata_port_wait_eh(ap);
|
||||
- ata_acpi_eject_device(handle);
|
||||
- }
|
||||
-
|
||||
- if (kobj && !is_dock_event) {
|
||||
- sprintf(event_string, "BAY_EVENT=%d", event);
|
||||
- kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
|
||||
- }
|
||||
-
|
||||
- kobject_put(kobj);
|
||||
}
|
||||
|
||||
static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct ata_device *dev = data;
|
||||
|
||||
- ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1);
|
||||
+ ata_acpi_handle_hotplug(dev->link->ap, dev, event);
|
||||
}
|
||||
|
||||
static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct ata_port *ap = data;
|
||||
|
||||
- ata_acpi_handle_hotplug(ap, NULL, event, 1);
|
||||
-}
|
||||
-
|
||||
-static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
|
||||
-{
|
||||
- struct ata_device *dev = data;
|
||||
-
|
||||
- ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0);
|
||||
-}
|
||||
-
|
||||
-static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
|
||||
-{
|
||||
- struct ata_port *ap = data;
|
||||
-
|
||||
- ata_acpi_handle_hotplug(ap, NULL, event, 0);
|
||||
+ ata_acpi_handle_hotplug(ap, NULL, event);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,9 +242,6 @@ void ata_acpi_associate(struct ata_host *host)
|
||||
ata_acpi_associate_ide_port(ap);
|
||||
|
||||
if (ap->acpi_handle) {
|
||||
- acpi_install_notify_handler(ap->acpi_handle,
|
||||
- ACPI_SYSTEM_NOTIFY,
|
||||
- ata_acpi_ap_notify, ap);
|
||||
/* we might be on a docking station */
|
||||
register_hotplug_dock_device(ap->acpi_handle,
|
||||
ata_acpi_ap_notify_dock, ap);
|
||||
@@ -327,9 +251,6 @@ void ata_acpi_associate(struct ata_host *host)
|
||||
struct ata_device *dev = &ap->link.device[j];
|
||||
|
||||
if (dev->acpi_handle) {
|
||||
- acpi_install_notify_handler(dev->acpi_handle,
|
||||
- ACPI_SYSTEM_NOTIFY,
|
||||
- ata_acpi_dev_notify, dev);
|
||||
/* we might be on a docking station */
|
||||
register_hotplug_dock_device(dev->acpi_handle,
|
||||
ata_acpi_dev_notify_dock, dev);
|
||||
@@ -1,206 +0,0 @@
|
||||
From: Myron Stowe <myron.stowe@hp.com>
|
||||
Subject: ACPI: Behave uniquely based on processor declaration definition type
|
||||
References: bnc#440062
|
||||
Patch-Mainline: yes
|
||||
Commit-ID: b26e9286fb438eb78bcdb68b67a3dbb8bc539125
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
|
||||
Associating a Local SAPIC with a processor object is dependent upon the
|
||||
processor object's definition type. CPUs declared as "Processor" should
|
||||
use the Local SAPIC's 'processor_id', and CPUs declared as "Device"
|
||||
should use the 'uid'. Note that for "Processor" declarations, even if a
|
||||
'_UID' child object exists, it has no bearing with respect to mapping
|
||||
Local SAPICs (see section 5.2.11.13 - Local SAPIC Structure; "Advanced
|
||||
Configuration and Power Interface Specification", Revision 3.0b).
|
||||
|
||||
This patch changes the lsapic mapping logic to rely on the distinction of
|
||||
how the processor object was declared - the mapping can't just try both
|
||||
types of matches regardless of declaration type and rely on one failing
|
||||
as is currently being done.
|
||||
|
||||
Signed-off-by: Myron Stowe <myron.stowe@hp.com>
|
||||
Signed-off-by: Len Brown <len.brown@intel.com>
|
||||
|
||||
---
|
||||
drivers/acpi/processor_core.c | 78 +++++++++++++++++++++++-------------------
|
||||
1 file changed, 44 insertions(+), 34 deletions(-)
|
||||
|
||||
Index: linux-2.6.27/drivers/acpi/processor_core.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/drivers/acpi/processor_core.c
|
||||
+++ linux-2.6.27/drivers/acpi/processor_core.c
|
||||
@@ -410,7 +410,7 @@ static int acpi_processor_remove_fs(stru
|
||||
/* Use the acpiid in MADT to map cpus in case of SMP */
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
-static int get_cpu_id(acpi_handle handle, u32 acpi_id) {return -1;}
|
||||
+static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id) { return -1; }
|
||||
#else
|
||||
|
||||
static struct acpi_table_madt *madt;
|
||||
@@ -429,27 +429,35 @@ static int map_lapic_id(struct acpi_subt
|
||||
}
|
||||
|
||||
static int map_lsapic_id(struct acpi_subtable_header *entry,
|
||||
- u32 acpi_id, int *apic_id)
|
||||
+ int device_declaration, u32 acpi_id, int *apic_id)
|
||||
{
|
||||
struct acpi_madt_local_sapic *lsapic =
|
||||
(struct acpi_madt_local_sapic *)entry;
|
||||
+ u32 tmp = (lsapic->id << 8) | lsapic->eid;
|
||||
+
|
||||
/* Only check enabled APICs*/
|
||||
- if (lsapic->lapic_flags & ACPI_MADT_ENABLED) {
|
||||
- /* First check against id */
|
||||
- if (lsapic->processor_id == acpi_id) {
|
||||
- *apic_id = (lsapic->id << 8) | lsapic->eid;
|
||||
- return 1;
|
||||
- /* Check against optional uid */
|
||||
- } else if (entry->length >= 16 &&
|
||||
- lsapic->uid == acpi_id) {
|
||||
- *apic_id = lsapic->uid;
|
||||
- return 1;
|
||||
- }
|
||||
- }
|
||||
+ if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))
|
||||
+ return 0;
|
||||
+
|
||||
+ /* Device statement declaration type */
|
||||
+ if (device_declaration) {
|
||||
+ if (entry->length < 16)
|
||||
+ printk(KERN_ERR PREFIX
|
||||
+ "Invalid LSAPIC with Device type processor (SAPIC ID %#x)\n",
|
||||
+ tmp);
|
||||
+ else if (lsapic->uid == acpi_id)
|
||||
+ goto found;
|
||||
+ /* Processor statement declaration type */
|
||||
+ } else if (lsapic->processor_id == acpi_id)
|
||||
+ goto found;
|
||||
+
|
||||
return 0;
|
||||
+found:
|
||||
+ *apic_id = tmp;
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
-static int map_madt_entry(u32 acpi_id)
|
||||
+static int map_madt_entry(int type, u32 acpi_id)
|
||||
{
|
||||
unsigned long madt_end, entry;
|
||||
int apic_id = -1;
|
||||
@@ -470,7 +478,7 @@ static int map_madt_entry(u32 acpi_id)
|
||||
if (map_lapic_id(header, acpi_id, &apic_id))
|
||||
break;
|
||||
} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
|
||||
- if (map_lsapic_id(header, acpi_id, &apic_id))
|
||||
+ if (map_lsapic_id(header, type, acpi_id, &apic_id))
|
||||
break;
|
||||
}
|
||||
entry += header->length;
|
||||
@@ -478,7 +486,7 @@ static int map_madt_entry(u32 acpi_id)
|
||||
return apic_id;
|
||||
}
|
||||
|
||||
-static int map_mat_entry(acpi_handle handle, u32 acpi_id)
|
||||
+static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
@@ -501,7 +509,7 @@ static int map_mat_entry(acpi_handle han
|
||||
if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
|
||||
map_lapic_id(header, acpi_id, &apic_id);
|
||||
} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
|
||||
- map_lsapic_id(header, acpi_id, &apic_id);
|
||||
+ map_lsapic_id(header, type, acpi_id, &apic_id);
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -510,14 +518,14 @@ exit:
|
||||
return apic_id;
|
||||
}
|
||||
|
||||
-static int get_cpu_id(acpi_handle handle, u32 acpi_id)
|
||||
+static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id)
|
||||
{
|
||||
int i;
|
||||
int apic_id = -1;
|
||||
|
||||
- apic_id = map_mat_entry(handle, acpi_id);
|
||||
+ apic_id = map_mat_entry(handle, type, acpi_id);
|
||||
if (apic_id == -1)
|
||||
- apic_id = map_madt_entry(acpi_id);
|
||||
+ apic_id = map_madt_entry(type, acpi_id);
|
||||
if (apic_id == -1)
|
||||
return apic_id;
|
||||
|
||||
@@ -533,15 +541,16 @@ static int get_cpu_id(acpi_handle handle
|
||||
Driver Interface
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
|
||||
+static int acpi_processor_get_info(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status = 0;
|
||||
union acpi_object object = { 0 };
|
||||
struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
|
||||
- int cpu_index;
|
||||
+ struct acpi_processor *pr;
|
||||
+ int cpu_index, device_declaration = 0;
|
||||
static int cpu0_initialized;
|
||||
|
||||
-
|
||||
+ pr = acpi_driver_data(device);
|
||||
if (!pr)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -562,22 +571,23 @@ static int acpi_processor_get_info(struc
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"No bus mastering arbitration control\n"));
|
||||
|
||||
- /* Check if it is a Device with HID and UID */
|
||||
- if (has_uid) {
|
||||
+ if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_HID)) {
|
||||
+ /*
|
||||
+ * Declared with "Device" statement; match _UID.
|
||||
+ * Note that we don't handle string _UIDs yet.
|
||||
+ */
|
||||
unsigned long long value;
|
||||
status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
|
||||
NULL, &value);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
- printk(KERN_ERR PREFIX "Evaluating processor _UID\n");
|
||||
+ printk(KERN_ERR PREFIX
|
||||
+ "Evaluating processor _UID [%#x]\n", status);
|
||||
return -ENODEV;
|
||||
}
|
||||
+ device_declaration = 1;
|
||||
pr->acpi_id = value;
|
||||
} else {
|
||||
- /*
|
||||
- * Evalute the processor object. Note that it is common on SMP to
|
||||
- * have the first (boot) processor with a valid PBLK address while
|
||||
- * all others have a NULL address.
|
||||
- */
|
||||
+ /* Declared with "Processor" statement; match ProcessorID */
|
||||
status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX "Evaluating processor object\n");
|
||||
@@ -590,7 +600,7 @@ static int acpi_processor_get_info(struc
|
||||
*/
|
||||
pr->acpi_id = object.processor.proc_id;
|
||||
}
|
||||
- cpu_index = get_cpu_id(pr->handle, pr->acpi_id);
|
||||
+ cpu_index = get_cpu_id(pr->handle, device_declaration, pr->acpi_id);
|
||||
|
||||
/* Handle UP system running SMP kernel, with no LAPIC in MADT */
|
||||
if (!cpu0_initialized && (cpu_index == -1) &&
|
||||
@@ -662,7 +672,7 @@ static int __cpuinit acpi_processor_star
|
||||
|
||||
pr = acpi_driver_data(device);
|
||||
|
||||
- result = acpi_processor_get_info(pr, device->flags.unique_id);
|
||||
+ result = acpi_processor_get_info(device);
|
||||
if (result) {
|
||||
/* Processor is physically not present */
|
||||
return 0;
|
||||
@@ -1,58 +0,0 @@
|
||||
From: Myron Stowe <myron.stowe@hp.com>
|
||||
Subject: ACPI: Disambiguate processor declaration type
|
||||
References: bnc#440062
|
||||
Patch-Mainline: yes
|
||||
Commit-ID: ad93a765c1834db031b5bf1c2baf2a50d0462ca4
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
|
||||
Declaring processors in ACPI namespace can be done using either a
|
||||
"Processor" definition or a "Device" definition (see section 8.4 -
|
||||
Declaring Processors; "Advanced Configuration and Power Interface
|
||||
Specification", Revision 3.0b). Currently the two processor
|
||||
declaration types are conflated.
|
||||
|
||||
This patch disambiguates the processor declaration's definition type
|
||||
enabling subsequent code to behave uniquely based explicitly on the
|
||||
declaration's type.
|
||||
|
||||
Signed-off-by: Myron Stowe <myron.stowe@hp.com>
|
||||
Signed-off-by: Len Brown <len.brown@intel.com>
|
||||
|
||||
---
|
||||
drivers/acpi/processor_core.c | 1 +
|
||||
drivers/acpi/scan.c | 2 +-
|
||||
include/acpi/acpi_drivers.h | 1 +
|
||||
3 files changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/acpi/processor_core.c
|
||||
+++ b/drivers/acpi/processor_core.c
|
||||
@@ -89,6 +89,7 @@ static int acpi_processor_handle_eject(s
|
||||
|
||||
|
||||
static const struct acpi_device_id processor_device_ids[] = {
|
||||
+ {ACPI_PROCESSOR_OBJECT_HID, 0},
|
||||
{ACPI_PROCESSOR_HID, 0},
|
||||
{"", 0},
|
||||
};
|
||||
--- a/drivers/acpi/scan.c
|
||||
+++ b/drivers/acpi/scan.c
|
||||
@@ -1002,7 +1002,7 @@ static void acpi_device_set_id(struct ac
|
||||
hid = ACPI_POWER_HID;
|
||||
break;
|
||||
case ACPI_BUS_TYPE_PROCESSOR:
|
||||
- hid = ACPI_PROCESSOR_HID;
|
||||
+ hid = ACPI_PROCESSOR_OBJECT_HID;
|
||||
break;
|
||||
case ACPI_BUS_TYPE_SYSTEM:
|
||||
hid = ACPI_SYSTEM_HID;
|
||||
--- a/include/acpi/acpi_drivers.h
|
||||
+++ b/include/acpi/acpi_drivers.h
|
||||
@@ -41,6 +41,7 @@
|
||||
*/
|
||||
|
||||
#define ACPI_POWER_HID "LNXPOWER"
|
||||
+#define ACPI_PROCESSOR_OBJECT_HID "ACPI_CPU"
|
||||
#define ACPI_PROCESSOR_HID "ACPI0007"
|
||||
#define ACPI_SYSTEM_HID "LNXSYSTM"
|
||||
#define ACPI_THERMAL_HID "LNXTHERM"
|
||||
@@ -1,67 +0,0 @@
|
||||
From: Alexey Starikovskiy <astarikovskiy@suse.de>
|
||||
Subject: ACPI: EC: Don't degrade to poll mode at storm automatically.
|
||||
References: bnc#446142
|
||||
Patch-Mainline: no
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
|
||||
Not all users of semi-broken EC devices want to degrade to poll mode, so
|
||||
give them right to choose.
|
||||
|
||||
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
|
||||
---
|
||||
|
||||
Documentation/kernel-parameters.txt | 5 +++++
|
||||
drivers/acpi/ec.c | 15 +++++++++++++++
|
||||
2 files changed, 20 insertions(+)
|
||||
|
||||
|
||||
--- a/Documentation/kernel-parameters.txt
|
||||
+++ b/Documentation/kernel-parameters.txt
|
||||
@@ -706,6 +706,11 @@ and is between 256 and 4096 characters.
|
||||
|
||||
eata= [HW,SCSI]
|
||||
|
||||
+ ec_intr= [HW,ACPI] ACPI Embedded Controller interrupt mode
|
||||
+ Format: <int>
|
||||
+ 0: polling mode
|
||||
+ non-0: interrupt mode (default)
|
||||
+
|
||||
edd= [EDD]
|
||||
Format: {"off" | "on" | "skip[mbr]"}
|
||||
|
||||
--- a/drivers/acpi/ec.c
|
||||
+++ b/drivers/acpi/ec.c
|
||||
@@ -121,6 +121,8 @@ static struct acpi_ec {
|
||||
spinlock_t curr_lock;
|
||||
} *boot_ec, *first_ec;
|
||||
|
||||
+int acpi_ec_intr = 1; /* Default is interrupt mode */
|
||||
+
|
||||
/*
|
||||
* Some Asus system have exchanged ECDT data/command IO addresses.
|
||||
*/
|
||||
@@ -902,6 +904,8 @@ static int ec_install_handlers(struct ac
|
||||
&acpi_ec_gpe_handler, ec);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
+ if (!acpi_ec_intr)
|
||||
+ set_bit(EC_FLAGS_NO_GPE, &ec->flags);
|
||||
acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
|
||||
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
|
||||
status = acpi_install_address_space_handler(ec->handle,
|
||||
@@ -1095,3 +1099,14 @@ static void __exit acpi_ec_exit(void)
|
||||
return;
|
||||
}
|
||||
#endif /* 0 */
|
||||
+
|
||||
+static int __init acpi_ec_set_intr_mode(char *str)
|
||||
+{
|
||||
+ if (!get_option(&str, &acpi_ec_intr)) {
|
||||
+ acpi_ec_intr = 0;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+__setup("ec_intr=", acpi_ec_set_intr_mode);
|
||||
@@ -1,29 +0,0 @@
|
||||
From: Myron Stowe <myron.stowe@hp.com>
|
||||
Subject: ACPI: 80 column adherence and spelling fix (no functional change)
|
||||
References: bnc#440062
|
||||
Patch-Mainline: yes
|
||||
Commit-ID: 5b53ed69158eeff115004f246193d07a083445f6
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
|
||||
Signed-off-by: Myron Stowe <myron.stowe@hp.com>
|
||||
Signed-off-by: Len Brown <len.brown@intel.com>
|
||||
|
||||
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
|
||||
index bc332fc..b57b1f0 100644
|
||||
--- a/drivers/acpi/processor_core.c
|
||||
+++ b/drivers/acpi/processor_core.c
|
||||
@@ -595,9 +595,10 @@ static int acpi_processor_get_info(struct acpi_device *device)
|
||||
}
|
||||
|
||||
/*
|
||||
- * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
|
||||
- * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
|
||||
- */
|
||||
+ * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
|
||||
+ * >>> 'acpi_get_processor_id(acpi_id, &id)' in
|
||||
+ * arch/xxx/acpi.c
|
||||
+ */
|
||||
pr->acpi_id = object.processor.proc_id;
|
||||
}
|
||||
cpu_index = get_cpu_id(pr->handle, device_declaration, pr->acpi_id);
|
||||
@@ -1,58 +0,0 @@
|
||||
From: Kurt Garloff <garloff@suse.de>
|
||||
Subject: Use SRAT table rev to use 8bit or 16/32bit PXM fields (ia64)
|
||||
References: bnc#503038
|
||||
|
||||
In SRAT v1, we had 8bit proximity domain (PXM) fields; SRAT v2 provides
|
||||
32bits for these. The new fields were reserved before.
|
||||
According to the ACPI spec, the OS must disregrard reserved fields.
|
||||
|
||||
ia64 did handle the PXM fields almost consistently, but depending on
|
||||
sgi's sn2 platform. This patch leaves the sn2 logic in, but does also
|
||||
use 16/32 bits for PXM if the SRAT has rev 2 or higher.
|
||||
|
||||
The patch also adds __init to the two pxm accessor functions, as they
|
||||
access __initdata now and are called from an __init function only anyway.
|
||||
|
||||
Note that the code only uses 16 bits for the PXM field in the processor
|
||||
proximity field; the patch does not address this as 16 bits are more than
|
||||
enough.
|
||||
|
||||
This is patch 3/3.
|
||||
|
||||
Signed-off-by: Kurt Garloff <garloff@suse.de>
|
||||
|
||||
---
|
||||
arch/ia64/kernel/acpi.c | 10 ++++++----
|
||||
1 file changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/arch/ia64/kernel/acpi.c
|
||||
+++ b/arch/ia64/kernel/acpi.c
|
||||
@@ -430,22 +430,24 @@ static u32 __devinitdata pxm_flag[PXM_FL
|
||||
static struct acpi_table_slit __initdata *slit_table;
|
||||
cpumask_t early_cpu_possible_map = CPU_MASK_NONE;
|
||||
|
||||
-static int get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa)
|
||||
+static int __init
|
||||
+get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa)
|
||||
{
|
||||
int pxm;
|
||||
|
||||
pxm = pa->proximity_domain_lo;
|
||||
- if (ia64_platform_is("sn2"))
|
||||
+ if (ia64_platform_is("sn2") || acpi_srat_revision >= 2)
|
||||
pxm += pa->proximity_domain_hi[0] << 8;
|
||||
return pxm;
|
||||
}
|
||||
|
||||
-static int get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma)
|
||||
+static int __init
|
||||
+get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma)
|
||||
{
|
||||
int pxm;
|
||||
|
||||
pxm = ma->proximity_domain;
|
||||
- if (!ia64_platform_is("sn2"))
|
||||
+ if (!ia64_platform_is("sn2") && acpi_srat_revision <= 1)
|
||||
pxm &= 0xff;
|
||||
|
||||
return pxm;
|
||||
@@ -1,51 +0,0 @@
|
||||
From: Kurt Garloff <garloff@suse.de>
|
||||
Subject: Store SRAT table revision
|
||||
References: bnc#503038
|
||||
|
||||
In SRAT v1, we had 8bit proximity domain (PXM) fields; SRAT v2 provides
|
||||
32bits for these. The new fields were reserved before.
|
||||
According to the ACPI spec, the OS must disregrard reserved fields.
|
||||
In order to know whether or not, we must know what version the SRAT
|
||||
table has.
|
||||
|
||||
This patch stores the SRAT table revision for later consumption
|
||||
by arch specific __init functions.
|
||||
|
||||
This is patch 1/3.
|
||||
|
||||
Signed-off-by: Kurt Garloff <garloff@suse.de>
|
||||
|
||||
---
|
||||
drivers/acpi/numa.c | 3 +++
|
||||
include/acpi/acpi_numa.h | 1 +
|
||||
2 files changed, 4 insertions(+)
|
||||
|
||||
--- a/drivers/acpi/numa.c
|
||||
+++ b/drivers/acpi/numa.c
|
||||
@@ -43,6 +43,8 @@ static int pxm_to_node_map[MAX_PXM_DOMAI
|
||||
static int node_to_pxm_map[MAX_NUMNODES]
|
||||
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
|
||||
|
||||
+unsigned char acpi_srat_revision __initdata;
|
||||
+
|
||||
int pxm_to_node(int pxm)
|
||||
{
|
||||
if (pxm < 0)
|
||||
@@ -225,6 +227,7 @@ static int __init acpi_parse_srat(struct
|
||||
return -EINVAL;
|
||||
|
||||
srat = (struct acpi_table_srat *)table;
|
||||
+ acpi_srat_revision = srat->header.revision;
|
||||
|
||||
return 0;
|
||||
}
|
||||
--- a/include/acpi/acpi_numa.h
|
||||
+++ b/include/acpi/acpi_numa.h
|
||||
@@ -15,6 +15,7 @@ extern int pxm_to_node(int);
|
||||
extern int node_to_pxm(int);
|
||||
extern void __acpi_map_pxm_to_node(int, int);
|
||||
extern int acpi_map_pxm_to_node(int);
|
||||
+extern unsigned char acpi_srat_revision;
|
||||
|
||||
#endif /* CONFIG_ACPI_NUMA */
|
||||
#endif /* __ACP_NUMA_H */
|
||||
@@ -1,41 +0,0 @@
|
||||
From: Kurt Garloff <garloff@suse.de>
|
||||
Subject: Use SRAT table rev to use 8bit or 32bit PXM fields (x86-64)
|
||||
References: bnc#503038
|
||||
|
||||
In SRAT v1, we had 8bit proximity domain (PXM) fields; SRAT v2 provides
|
||||
32bits for these. The new fields were reserved before.
|
||||
According to the ACPI spec, the OS must disregrard reserved fields.
|
||||
|
||||
x86-64 was rather inconsistent prior to this patch; it used 8 bits
|
||||
for the pxm field in cpu_affinity, but 32 bits in mem_affinity.
|
||||
This patch makes it consistent: Either use 8 bits consistently (SRAT
|
||||
rev 1 or lower) or 32 bits (SRAT rev 2 or higher).
|
||||
|
||||
This is patch 2/3.
|
||||
|
||||
Signed-off-by: Kurt Garloff <garloff@suse.de>
|
||||
|
||||
---
|
||||
arch/x86/mm/srat_64.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
--- a/arch/x86/mm/srat_64.c
|
||||
+++ b/arch/x86/mm/srat_64.c
|
||||
@@ -133,6 +133,8 @@ acpi_numa_processor_affinity_init(struct
|
||||
if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
|
||||
return;
|
||||
pxm = pa->proximity_domain_lo;
|
||||
+ if (acpi_srat_revision >= 2)
|
||||
+ pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8;
|
||||
node = setup_node(pxm);
|
||||
if (node < 0) {
|
||||
printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
|
||||
@@ -243,6 +245,8 @@ acpi_numa_memory_affinity_init(struct ac
|
||||
start = ma->base_address;
|
||||
end = start + ma->length;
|
||||
pxm = ma->proximity_domain;
|
||||
+ if (acpi_srat_revision <= 1)
|
||||
+ pxm &= 0xff;
|
||||
node = setup_node(pxm);
|
||||
if (node < 0) {
|
||||
printk(KERN_ERR "SRAT: Too many proximity domains.\n");
|
||||
@@ -1,104 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: Avoid critical temp shutdowns on specific ThinkPad T4x(p) and R40
|
||||
References: https://bugzilla.novell.com/show_bug.cgi?id=333043
|
||||
|
||||
---
|
||||
drivers/acpi/thermal.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 73 insertions(+)
|
||||
|
||||
--- a/drivers/acpi/thermal.c
|
||||
+++ b/drivers/acpi/thermal.c
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/reboot.h>
|
||||
+#include <linux/dmi.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
@@ -1640,6 +1641,66 @@ static int acpi_thermal_get_info(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static struct dmi_system_id thermal_psv_dmi_table[] = {
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad T41",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T41"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad T42",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T42"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad T43",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T43"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad T41p",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T41p"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad T42p",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T42p"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad T43p",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T43p"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad R40",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad R40"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad R50p",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad R50p"),
|
||||
+ },
|
||||
+ },
|
||||
+ {},
|
||||
+};
|
||||
+
|
||||
static int acpi_thermal_add(struct acpi_device *device)
|
||||
{
|
||||
int result = 0;
|
||||
@@ -1670,6 +1731,18 @@ static int acpi_thermal_add(struct acpi_
|
||||
if (result)
|
||||
goto free_memory;
|
||||
|
||||
+ if (dmi_check_system(thermal_psv_dmi_table)) {
|
||||
+ if (tz->trips.passive.flags.valid &&
|
||||
+ tz->trips.passive.temperature > CELSIUS_TO_KELVIN(85)) {
|
||||
+ printk (KERN_INFO "Adjust passive trip point from %lu"
|
||||
+ " to %lu\n",
|
||||
+ KELVIN_TO_CELSIUS(tz->trips.passive.temperature),
|
||||
+ KELVIN_TO_CELSIUS(tz->trips.passive.temperature - 150));
|
||||
+ tz->trips.passive.temperature -= 150;
|
||||
+ acpi_thermal_set_polling(tz, 5);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
result = acpi_thermal_add_fs(device);
|
||||
if (result)
|
||||
goto unregister_thermal_zone;
|
||||
@@ -1,96 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: Introduce acpi_root_table=rsdt boot param and dmi list to force rsdt
|
||||
Patch-mainline: not yet
|
||||
References: http://bugzilla.kernel.org/show_bug.cgi?id=8246
|
||||
|
||||
This one is part of a patch series:
|
||||
acpi_thinkpad_introduce_acpi_root_table_boot_param.patch
|
||||
acpi_thinkpad_introduce_acpica_rsdt_global_variable.patch
|
||||
acpi_thinkpad_remove_R40e_c-state_blacklist.patch
|
||||
|
||||
Blacklist R40e, R51e and T40, T40p, T41, T41p, T42, T42p, R50 and R50p
|
||||
ThinkPads to use the RSDT instead of the XSDT.
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Tested-by: Mark Doughty <me@markdoughty.co.uk>
|
||||
CC: Yakui Zhao <yakui.zhao@intel.com>
|
||||
|
||||
---
|
||||
Documentation/kernel-parameters.txt | 5 ++++
|
||||
drivers/acpi/tables.c | 37 ++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 42 insertions(+)
|
||||
|
||||
--- a/Documentation/kernel-parameters.txt
|
||||
+++ b/Documentation/kernel-parameters.txt
|
||||
@@ -237,6 +237,11 @@ and is between 256 and 4096 characters.
|
||||
to assume that this machine's pmtimer latches its value
|
||||
and always returns good values.
|
||||
|
||||
+ acpi_root_table= [X86,ACPI]
|
||||
+ { rsdt }
|
||||
+ rsdt: Take RSDT address for fetching
|
||||
+ ACPI tables (instead of XSDT)
|
||||
+
|
||||
agp= [AGP]
|
||||
{ off | try_unsupported }
|
||||
off: disable AGP support
|
||||
--- a/drivers/acpi/tables.c
|
||||
+++ b/drivers/acpi/tables.c
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bootmem.h>
|
||||
+#include <linux/dmi.h>
|
||||
|
||||
#define PREFIX "ACPI: "
|
||||
|
||||
@@ -282,6 +283,37 @@ static void __init check_multiple_madt(v
|
||||
return;
|
||||
}
|
||||
|
||||
+static struct dmi_system_id __initdata acpi_rsdt_dmi_table[] = {
|
||||
+ {
|
||||
+ .ident = "ThinkPad ", /* R40e, broken C-states */
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR, "IBM"),
|
||||
+ DMI_MATCH(DMI_BIOS_VERSION, "1SET")},
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "ThinkPad ", /* R50e, slow booting */
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR, "IBM"),
|
||||
+ DMI_MATCH(DMI_BIOS_VERSION, "1WET")},
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "ThinkPad ", /* T40, T40p, T41, T41p, T42, T42p
|
||||
+ R50, R50p */
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR, "IBM"),
|
||||
+ DMI_MATCH(DMI_BIOS_VERSION, "1RET")},
|
||||
+ },
|
||||
+ {}
|
||||
+};
|
||||
+
|
||||
+static int __init acpi_force_rsdt(char *opt)
|
||||
+{
|
||||
+ if (!strcmp(opt, "rsdt"))
|
||||
+ acpi_gbl_force_rsdt = 1;
|
||||
+ return 0;
|
||||
+}
|
||||
+early_param("acpi_root_table", acpi_force_rsdt);
|
||||
+
|
||||
/*
|
||||
* acpi_table_init()
|
||||
*
|
||||
@@ -295,6 +327,11 @@ int __init acpi_table_init(void)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
+ if (dmi_check_system(acpi_rsdt_dmi_table))
|
||||
+ acpi_gbl_force_rsdt = 1;
|
||||
+ if (acpi_gbl_force_rsdt)
|
||||
+ printk(KERN_INFO "Using RSDT as ACPI root table\n");
|
||||
+
|
||||
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 1;
|
||||
@@ -1,53 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: ACPICA: Add acpi_gbl_force_rsdt variable
|
||||
Patch-mainline: not yet
|
||||
References: http://bugzilla.kernel.org/show_bug.cgi?id=8246
|
||||
|
||||
This one is part of a patch series:
|
||||
acpi_thinkpad_introduce_acpi_root_table_boot_param.patch
|
||||
acpi_thinkpad_introduce_acpica_rsdt_global_variable.patch
|
||||
acpi_thinkpad_remove_R40e_c-state_blacklist.patch
|
||||
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Tested-by: Mark Doughty <me@markdoughty.co.uk>
|
||||
|
||||
|
||||
---
|
||||
drivers/acpi/tables/tbutils.c | 3 ++-
|
||||
drivers/acpi/utilities/utglobal.c | 1 +
|
||||
include/acpi/acglobal.h | 1 +
|
||||
3 files changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/acpi/tables/tbutils.c
|
||||
+++ b/drivers/acpi/tables/tbutils.c
|
||||
@@ -420,7 +420,8 @@ acpi_tb_parse_root_table(acpi_physical_a
|
||||
|
||||
/* Differentiate between RSDT and XSDT root tables */
|
||||
|
||||
- if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
|
||||
+ if (rsdp->revision > 1 && rsdp->xsdt_physical_address
|
||||
+ && !acpi_gbl_force_rsdt) {
|
||||
/*
|
||||
* Root table is an XSDT (64-bit physical addresses). We must use the
|
||||
* XSDT if the revision is > 1 and the XSDT pointer is present, as per
|
||||
--- a/drivers/acpi/utilities/utglobal.c
|
||||
+++ b/drivers/acpi/utilities/utglobal.c
|
||||
@@ -76,6 +76,7 @@ u8 acpi_gbl_method_executing = FALSE;
|
||||
/* System flags */
|
||||
|
||||
u32 acpi_gbl_startup_flags = 0;
|
||||
+int acpi_gbl_force_rsdt = 0;
|
||||
|
||||
/* System starts uninitialized */
|
||||
|
||||
--- a/include/acpi/acglobal.h
|
||||
+++ b/include/acpi/acglobal.h
|
||||
@@ -246,6 +246,7 @@ ACPI_EXTERN u8 acpi_gbl_system_awake_and
|
||||
|
||||
extern u8 acpi_gbl_shutdown;
|
||||
extern u32 acpi_gbl_startup_flags;
|
||||
+extern int acpi_gbl_force_rsdt;
|
||||
extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
|
||||
extern const char *acpi_gbl_highest_dstate_names[4];
|
||||
extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
|
||||
@@ -1,98 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: Remove R40e c-state blacklist
|
||||
Patch-mainline: not yet
|
||||
References: http://bugzilla.kernel.org/show_bug.cgi?id=8246
|
||||
|
||||
This one is part of a patch series:
|
||||
acpi_thinkpad_introduce_acpi_root_table_boot_param.patch
|
||||
acpi_thinkpad_introduce_acpica_rsdt_global_variable.patch
|
||||
acpi_thinkpad_remove_R40e_c-state_blacklist.patch
|
||||
|
||||
|
||||
The FADT pointed to through XSDT is wrong on this (and similar)
|
||||
machines.
|
||||
The HW addresses to switch C-states are coming from the FADT.
|
||||
When using the FADT pointed to in the RSDT the info is correct.
|
||||
Previous patches blacklist this machine to use the right FADT and
|
||||
C-states finally work fine.
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Tested-by: Mark Doughty <me@markdoughty.co.uk>
|
||||
|
||||
Remove R40e c-state blacklist
|
||||
|
||||
The FADT pointed to through XSDT is wrong on this (and similar) machines.
|
||||
The HW addresses to switch C-states are coming from the FADT.
|
||||
When using the FADT pointed to in the RSDT the info is correct.
|
||||
Previous patches blacklist this machine to use the right FADT and
|
||||
C-states finally work fine.
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Tested-by: Mark Doughty <me@markdoughty.co.uk>
|
||||
CC: Yakui Zhao <yakui.zhao@intel.com>
|
||||
|
||||
|
||||
---
|
||||
drivers/acpi/processor_idle.c | 51 ------------------------------------------
|
||||
1 file changed, 51 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/processor_idle.c
|
||||
+++ b/drivers/acpi/processor_idle.c
|
||||
@@ -127,57 +127,6 @@ static int set_max_cstate(const struct d
|
||||
/* Actually this shouldn't be __cpuinitdata, would be better to fix the
|
||||
callers to only run once -AK */
|
||||
static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = {
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET70WW")}, (void *)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW")}, (void *)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET43WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET45WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET47WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET50WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET52WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET55WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET56WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET59WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET61WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET62WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET64WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET65WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET68WW") }, (void*)1},
|
||||
- { set_max_cstate, "Medion 41700", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"R01-A1J")}, (void *)1},
|
||||
{ set_max_cstate, "Clevo 5600D", {
|
||||
DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
|
||||
DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")},
|
||||
@@ -1,56 +0,0 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: Do not use video backlight switching for Lenovo ThinkPads
|
||||
Patch-Mainline: never
|
||||
|
||||
Mainline will go the IGD driver way which is too new and untested for
|
||||
SLE11.
|
||||
|
||||
---
|
||||
drivers/acpi/video.c | 17 ++++++++++++++---
|
||||
drivers/acpi/video_detect.c | 2 +-
|
||||
2 files changed, 15 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/video.c
|
||||
+++ b/drivers/acpi/video.c
|
||||
@@ -731,7 +731,7 @@ static void acpi_video_device_find_cap(s
|
||||
{
|
||||
acpi_handle h_dummy1;
|
||||
u32 max_level = 0;
|
||||
-
|
||||
+ unsigned long acpi_video_support;
|
||||
|
||||
memset(&device->cap, 0, sizeof(device->cap));
|
||||
|
||||
@@ -759,8 +759,19 @@ static void acpi_video_device_find_cap(s
|
||||
device->cap._DSS = 1;
|
||||
}
|
||||
|
||||
- if (acpi_video_backlight_support())
|
||||
- max_level = acpi_video_init_brightness(device);
|
||||
+ acpi_video_support = acpi_video_backlight_support();
|
||||
+ if (acpi_video_support) {
|
||||
+ /*
|
||||
+ * Ugly SLE11 hack to let thinkpad_acpi handle brightness on
|
||||
+ * ThinkPad IGD devices
|
||||
+ */
|
||||
+ if (dmi_name_in_vendors("LENOVO") &&
|
||||
+ (acpi_video_support & ACPI_VIDEO_IGD))
|
||||
+ brightness_switch_enabled = 0;
|
||||
+ else
|
||||
+ max_level = acpi_video_init_brightness(device);
|
||||
+ } else
|
||||
+ brightness_switch_enabled = 0;
|
||||
|
||||
if (device->cap._BCL && device->cap._BCM && max_level > 0) {
|
||||
int result;
|
||||
--- a/drivers/acpi/video_detect.c
|
||||
+++ b/drivers/acpi/video_detect.c
|
||||
@@ -217,7 +217,7 @@ int acpi_video_backlight_support(void)
|
||||
return 1;
|
||||
|
||||
/* Then go the default way */
|
||||
- return acpi_video_support & ACPI_VIDEO_BACKLIGHT;
|
||||
+ return acpi_video_support & (ACPI_VIDEO_BACKLIGHT | ACPI_VIDEO_IGD);
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_video_backlight_support);
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
From: Bob Moore <robert.moore@intel.com>
|
||||
Subject: ACPICA: x2APIC support: changes for MADT and SRAT ACPI tables
|
||||
References: fate 303948 and fate 303984
|
||||
Patch-Mainline: in 2.6.28
|
||||
Commit-ID: 1d7cc03049f7c9c5cced9208a39316c5245ef314
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
|
||||
Support for the x2APIC. There are 2 new subtables for the MADT and
|
||||
one new subtable for the SRAT. Includes disassembler and acpisrc
|
||||
support. Data from the Intel 64 Architecture x2APIC Specification,
|
||||
June 2008.
|
||||
|
||||
Signed-off-by: Bob Moore <robert.moore@intel.com>
|
||||
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
Signed-off-by: Len Brown <len.brown@intel.com>
|
||||
|
||||
diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h
|
||||
index f53faca..0c1ed38 100644
|
||||
--- a/include/acpi/acdisasm.h
|
||||
+++ b/include/acpi/acdisasm.h
|
||||
@@ -186,6 +186,8 @@ extern struct acpi_dmtable_info acpi_dm_table_info_madt5[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_madt6[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_madt7[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_madt8[];
|
||||
+extern struct acpi_dmtable_info acpi_dm_table_info_madt9[];
|
||||
+extern struct acpi_dmtable_info acpi_dm_table_info_madt10[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_madt_hdr[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_mcfg[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_mcfg0[];
|
||||
@@ -197,8 +199,10 @@ extern struct acpi_dmtable_info acpi_dm_table_info_slit[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_spcr[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_spmi[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_srat[];
|
||||
+extern struct acpi_dmtable_info acpi_dm_table_info_srat_hdr[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_srat0[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_srat1[];
|
||||
+extern struct acpi_dmtable_info acpi_dm_table_info_srat2[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_tcpa[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_wdrt[];
|
||||
|
||||
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
|
||||
index d38f9be..63f5b4c 100644
|
||||
--- a/include/acpi/actbl1.h
|
||||
+++ b/include/acpi/actbl1.h
|
||||
@@ -908,7 +908,9 @@ enum acpi_madt_type {
|
||||
ACPI_MADT_TYPE_IO_SAPIC = 6,
|
||||
ACPI_MADT_TYPE_LOCAL_SAPIC = 7,
|
||||
ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8,
|
||||
- ACPI_MADT_TYPE_RESERVED = 9 /* 9 and greater are reserved */
|
||||
+ ACPI_MADT_TYPE_LOCAL_X2APIC = 9,
|
||||
+ ACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10,
|
||||
+ ACPI_MADT_TYPE_RESERVED = 11 /* 11 and greater are reserved */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1009,6 +1011,26 @@ struct acpi_madt_interrupt_source {
|
||||
|
||||
#define ACPI_MADT_CPEI_OVERRIDE (1)
|
||||
|
||||
+/* 9: Processor Local X2_APIC (07/2008) */
|
||||
+
|
||||
+struct acpi_madt_local_x2apic {
|
||||
+ struct acpi_subtable_header header;
|
||||
+ u16 reserved; /* Reserved - must be zero */
|
||||
+ u32 local_apic_id; /* Processor X2_APIC ID */
|
||||
+ u32 lapic_flags;
|
||||
+ u32 uid; /* Extended X2_APIC processor ID */
|
||||
+};
|
||||
+
|
||||
+/* 10: Local X2APIC NMI (07/2008) */
|
||||
+
|
||||
+struct acpi_madt_local_x2apic_nmi {
|
||||
+ struct acpi_subtable_header header;
|
||||
+ u16 inti_flags;
|
||||
+ u32 uid; /* Processor X2_APIC ID */
|
||||
+ u8 lint; /* LINTn to which NMI is connected */
|
||||
+ u8 reserved[3];
|
||||
+};
|
||||
+
|
||||
/*
|
||||
* Common flags fields for MADT subtables
|
||||
*/
|
||||
@@ -1150,10 +1172,15 @@ struct acpi_table_srat {
|
||||
enum acpi_srat_type {
|
||||
ACPI_SRAT_TYPE_CPU_AFFINITY = 0,
|
||||
ACPI_SRAT_TYPE_MEMORY_AFFINITY = 1,
|
||||
- ACPI_SRAT_TYPE_RESERVED = 2
|
||||
+ ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY = 2,
|
||||
+ ACPI_SRAT_TYPE_RESERVED = 3 /* 3 and greater are reserved */
|
||||
};
|
||||
|
||||
-/* SRAT sub-tables */
|
||||
+/*
|
||||
+ * SRAT Sub-tables, correspond to Type in struct acpi_subtable_header
|
||||
+ */
|
||||
+
|
||||
+/* 0: Processor Local APIC/SAPIC Affinity */
|
||||
|
||||
struct acpi_srat_cpu_affinity {
|
||||
struct acpi_subtable_header header;
|
||||
@@ -1165,9 +1192,7 @@ struct acpi_srat_cpu_affinity {
|
||||
u32 reserved; /* Reserved, must be zero */
|
||||
};
|
||||
|
||||
-/* Flags */
|
||||
-
|
||||
-#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */
|
||||
+/* 1: Memory Affinity */
|
||||
|
||||
struct acpi_srat_mem_affinity {
|
||||
struct acpi_subtable_header header;
|
||||
@@ -1186,6 +1211,20 @@ struct acpi_srat_mem_affinity {
|
||||
#define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1) /* 01: Memory region is hot pluggable */
|
||||
#define ACPI_SRAT_MEM_NON_VOLATILE (1<<2) /* 02: Memory region is non-volatile */
|
||||
|
||||
+/* 2: Processor Local X2_APIC Affinity (07/2008) */
|
||||
+
|
||||
+struct acpi_srat_x2apic_cpu_affinity {
|
||||
+ struct acpi_subtable_header header;
|
||||
+ u16 reserved; /* Reserved, must be zero */
|
||||
+ u32 proximity_domain;
|
||||
+ u32 apic_id;
|
||||
+ u32 flags;
|
||||
+};
|
||||
+
|
||||
+/* Flags for struct acpi_srat_cpu_affinity and struct acpi_srat_x2apic_cpu_affinity */
|
||||
+
|
||||
+#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */
|
||||
+
|
||||
/*******************************************************************************
|
||||
*
|
||||
* TCPA - Trusted Computing Platform Alliance table
|
||||
@@ -1,208 +0,0 @@
|
||||
From: Andreas Herrmann <andreas.herrmann3@amd.com>
|
||||
Subject: x86: Fix CPU llc_shared_map information for AMD Magny-Cours
|
||||
References: fate#307306
|
||||
Patch-Mainline: yes
|
||||
Commit-ID: 4a376ec3a2599c02207cd4cbd5dbf73783548463
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
|
||||
Construct entire NodeID and use it as cpu_llc_id. Thus internal node
|
||||
siblings are stored in llc_shared_map.
|
||||
|
||||
Signed-off-by: Andreas Herrmann <andreas.herrmann3@amd.com>
|
||||
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
|
||||
|
||||
---
|
||||
arch/x86/kernel/cpu/amd.c | 62 +++++++++++++++++++++++++++++++++++++++++
|
||||
arch/x86/kernel/cpu/amd_64.c | 64 +++++++++++++++++++++++++++++++++++++++++++
|
||||
include/asm-x86/cpufeature.h | 1
|
||||
3 files changed, 127 insertions(+)
|
||||
|
||||
Index: linux-2.6.27-SLE11_BRANCH/arch/x86/kernel/cpu/amd.c
|
||||
===================================================================
|
||||
--- linux-2.6.27-SLE11_BRANCH.orig/arch/x86/kernel/cpu/amd.c
|
||||
+++ linux-2.6.27-SLE11_BRANCH/arch/x86/kernel/cpu/amd.c
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/apic.h>
|
||||
+#include <asm/pci-direct.h>
|
||||
|
||||
#include <mach_apic.h>
|
||||
#include "cpu.h"
|
||||
@@ -38,6 +39,64 @@ static void __cpuinit early_init_amd(str
|
||||
set_cpu_cap(c, X86_FEATURE_K6_MTRR);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Fixup core topology information for AMD multi-node processors.
|
||||
+ * Assumption 1: Number of cores in each internal node is the same.
|
||||
+ * Assumption 2: Mixed systems with both single-node and dual-node
|
||||
+ * processors are not supported.
|
||||
+ */
|
||||
+#ifdef CONFIG_X86_HT
|
||||
+static void __cpuinit amd_fixup_dcm(struct cpuinfo_x86 *c)
|
||||
+{
|
||||
+#ifdef CONFIG_PCI
|
||||
+ u32 t, cpn;
|
||||
+ u8 n, n_id;
|
||||
+ int cpu = smp_processor_id();
|
||||
+
|
||||
+ /* fixup topology information only once for a core */
|
||||
+ if (cpu_has(c, X86_FEATURE_AMD_DCM))
|
||||
+ return;
|
||||
+
|
||||
+ /* check for multi-node processor on boot cpu */
|
||||
+ t = read_pci_config(0, 24, 3, 0xe8);
|
||||
+ if (!(t & (1 << 29)))
|
||||
+ return;
|
||||
+
|
||||
+ set_cpu_cap(c, X86_FEATURE_AMD_DCM);
|
||||
+
|
||||
+ /* cores per node: each internal node has half the number of cores */
|
||||
+ cpn = c->x86_max_cores >> 1;
|
||||
+
|
||||
+ /* even-numbered NB_id of this dual-node processor */
|
||||
+ n = c->phys_proc_id << 1;
|
||||
+
|
||||
+ /*
|
||||
+ * determine internal node id and assign cores fifty-fifty to
|
||||
+ * each node of the dual-node processor
|
||||
+ */
|
||||
+ t = read_pci_config(0, 24 + n, 3, 0xe8);
|
||||
+ n = (t>>30) & 0x3;
|
||||
+ if (n == 0) {
|
||||
+ if (c->cpu_core_id < cpn)
|
||||
+ n_id = 0;
|
||||
+ else
|
||||
+ n_id = 1;
|
||||
+ } else {
|
||||
+ if (c->cpu_core_id < cpn)
|
||||
+ n_id = 1;
|
||||
+ else
|
||||
+ n_id = 0;
|
||||
+ }
|
||||
+
|
||||
+ /* compute entire NodeID, use llc_shared_map to store sibling info */
|
||||
+ per_cpu(cpu_llc_id, cpu) = (c->phys_proc_id << 1) + n_id;
|
||||
+
|
||||
+ /* fixup core id to be in range from 0 to cpn */
|
||||
+ c->cpu_core_id = c->cpu_core_id % cpn;
|
||||
+#endif
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static void __cpuinit init_amd(struct cpuinfo_x86 *c)
|
||||
{
|
||||
u32 l, h;
|
||||
@@ -250,6 +309,9 @@ static void __cpuinit init_amd(struct cp
|
||||
printk(KERN_INFO "CPU %d(%d) -> Core %d\n",
|
||||
cpu, c->x86_max_cores, c->cpu_core_id);
|
||||
}
|
||||
+ /* fixup topology information on multi-node processors */
|
||||
+ if ((c->x86 == 0x10) && (c->x86_model == 9))
|
||||
+ amd_fixup_dcm(c);
|
||||
#endif
|
||||
|
||||
if (cpuid_eax(0x80000000) >= 0x80000006) {
|
||||
Index: linux-2.6.27-SLE11_BRANCH/include/asm-x86/cpufeature.h
|
||||
===================================================================
|
||||
--- linux-2.6.27-SLE11_BRANCH.orig/include/asm-x86/cpufeature.h
|
||||
+++ linux-2.6.27-SLE11_BRANCH/include/asm-x86/cpufeature.h
|
||||
@@ -84,6 +84,7 @@
|
||||
#define X86_FEATURE_AMDC1E (3*32+21) /* AMD C1E detected */
|
||||
#define X86_FEATURE_XTOPOLOGY (3*32+22) /* cpu topology enum extensions */
|
||||
#define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */
|
||||
+#define X86_FEATURE_AMD_DCM (3*32+27) /* multi-node processor */
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
|
||||
#define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */
|
||||
Index: linux-2.6.27-SLE11_BRANCH/arch/x86/kernel/cpu/amd_64.c
|
||||
===================================================================
|
||||
--- linux-2.6.27-SLE11_BRANCH.orig/arch/x86/kernel/cpu/amd_64.c
|
||||
+++ linux-2.6.27-SLE11_BRANCH/arch/x86/kernel/cpu/amd_64.c
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <asm/numa_64.h>
|
||||
#include <asm/mmconfig.h>
|
||||
#include <asm/cacheflush.h>
|
||||
+#include <asm/pci-direct.h>
|
||||
|
||||
#include <mach_apic.h>
|
||||
|
||||
@@ -31,6 +32,64 @@ static int __cpuinit nearby_node(int api
|
||||
#endif
|
||||
|
||||
/*
|
||||
+ * Fixup core topology information for AMD multi-node processors.
|
||||
+ * Assumption 1: Number of cores in each internal node is the same.
|
||||
+ * Assumption 2: Mixed systems with both single-node and dual-node
|
||||
+ * processors are not supported.
|
||||
+ */
|
||||
+#ifdef CONFIG_X86_HT
|
||||
+static void __cpuinit amd_fixup_dcm(struct cpuinfo_x86 *c)
|
||||
+{
|
||||
+#ifdef CONFIG_PCI
|
||||
+ u32 t, cpn;
|
||||
+ u8 n, n_id;
|
||||
+ int cpu = smp_processor_id();
|
||||
+
|
||||
+ /* fixup topology information only once for a core */
|
||||
+ if (cpu_has(c, X86_FEATURE_AMD_DCM))
|
||||
+ return;
|
||||
+
|
||||
+ /* check for multi-node processor on boot cpu */
|
||||
+ t = read_pci_config(0, 24, 3, 0xe8);
|
||||
+ if (!(t & (1 << 29)))
|
||||
+ return;
|
||||
+
|
||||
+ set_cpu_cap(c, X86_FEATURE_AMD_DCM);
|
||||
+
|
||||
+ /* cores per node: each internal node has half the number of cores */
|
||||
+ cpn = c->x86_max_cores >> 1;
|
||||
+
|
||||
+ /* even-numbered NB_id of this dual-node processor */
|
||||
+ n = c->phys_proc_id << 1;
|
||||
+
|
||||
+ /*
|
||||
+ * determine internal node id and assign cores fifty-fifty to
|
||||
+ * each node of the dual-node processor
|
||||
+ */
|
||||
+ t = read_pci_config(0, 24 + n, 3, 0xe8);
|
||||
+ n = (t>>30) & 0x3;
|
||||
+ if (n == 0) {
|
||||
+ if (c->cpu_core_id < cpn)
|
||||
+ n_id = 0;
|
||||
+ else
|
||||
+ n_id = 1;
|
||||
+ } else {
|
||||
+ if (c->cpu_core_id < cpn)
|
||||
+ n_id = 1;
|
||||
+ else
|
||||
+ n_id = 0;
|
||||
+ }
|
||||
+
|
||||
+ /* compute entire NodeID, use llc_shared_map to store sibling info */
|
||||
+ per_cpu(cpu_llc_id, cpu) = (c->phys_proc_id << 1) + n_id;
|
||||
+
|
||||
+ /* fixup core id to be in range from 0 to cpn */
|
||||
+ c->cpu_core_id = c->cpu_core_id % cpn;
|
||||
+#endif
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+/*
|
||||
* On a AMD dual core setup the lower bits of the APIC id distingush the cores.
|
||||
* Assumes number of cores is a power of two.
|
||||
*/
|
||||
@@ -49,6 +108,11 @@ static void __cpuinit amd_detect_cmp(str
|
||||
c->cpu_core_id = c->initial_apicid & ((1 << bits)-1);
|
||||
/* Convert the initial APIC ID into the socket ID */
|
||||
c->phys_proc_id = c->initial_apicid >> bits;
|
||||
+#ifdef CONFIG_X86_HT
|
||||
+ /* fixup topology information on multi-node processors */
|
||||
+ if ((c->x86 == 0x10) && (c->x86_model == 9))
|
||||
+ amd_fixup_dcm(c);
|
||||
+#endif
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
node = c->phys_proc_id;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user