Updated kernel (2.6.27.41).

This commit is contained in:
Arne Fitzenreiter
2009-12-10 23:45:39 +01:00
parent fd6c668a58
commit e69f1bf2e5
1877 changed files with 35 additions and 1625481 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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)) {

View File

@@ -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,

View File

@@ -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,

View File

@@ -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)
{

View File

@@ -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(&current->fs->lock);
+ root = current->fs->root;
+ path_get(&current->fs->root);
+ read_unlock(&current->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 */

View File

@@ -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(&current->fs->root);
read_unlock(&current->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);

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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)))

View File

@@ -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);

View File

@@ -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;
};
/*

View 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));

View File

@@ -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;
}

View File

@@ -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);
}

View 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);
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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.

View File

@@ -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;

View File

@@ -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);
}

View 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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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(&current->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(&current->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);

View File

@@ -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 *);

View File

@@ -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 *);

View File

@@ -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 *);

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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)

View 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);

View File

@@ -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.

View File

@@ -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 *);

View File

@@ -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);

View File

@@ -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 *);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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)

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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");
+ }
}
}

View File

@@ -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

View File

@@ -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);
-

View File

@@ -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
*/

View File

@@ -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:

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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;

View File

@@ -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"

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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");

View File

@@ -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;

View File

@@ -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;

View File

@@ -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];

View File

@@ -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")},

View File

@@ -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);

View File

@@ -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

View File

@@ -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