Discussion:
[linux-lvm] lvcreate from a setuid-root binary
Christoph Pleger
2018-11-15 16:39:56 UTC
Permalink
Hello,

I am calling lvcreate from a setuid-binary, which internally calls
setreuid(), so that not only effective and saved UIDs, but also the real
UID is set to 0. From _nonroot_warning() in lvmcmdline.c I see that LVM
command line tools expect that.

Unfortunately - though these UIDs are all set to 0 - lvcreate still does
not work for me. That is, it does work when I call my setuid-binary as a
non-root user from the command line, but it does not work when I call my
setuid-binary from PAM module pam_exec - and that is what I need my
program for. I let my program send lvcreate output to a file and that
file has the following content:

device-mapper: version ioctl on failed: Permission denied
Incompatible libdevmapper 1.02.137 (2016-11-30) and kernel driver
(unknown version).
striped: Required device-mapper target(s) not detected in your kernel.
Run `lvcreate --help' for more information.

What might be the problem here so that lvcreate gives these errors
though all UIDs are 0?

Regards
Christoph
Alasdair G Kergon
2018-11-15 17:57:18 UTC
Permalink
Post by Christoph Pleger
I am calling lvcreate from a setuid-binary, which internally calls
Let's stop there. The fact you're asking a question about setuid
suggests you don't understand enough to be able to use it safely.

Seriously, never use setuid for anything until you have a thorough
understanding of its internals (userspace and kernel) and ld-linux,
capabilities, process contexts, acls, selinux etc. It's just too easy
to make your system insecure because of something you didn't even
realise you had to consider! (I could tell you some funny stories...)

Go back to the beginning and describe the original problem you are
trying to solve and the constraints you have and ask for advice about
ways to achieve it.

Alasdair
Christoph Pleger
2018-11-16 13:43:10 UTC
Permalink
Hello,
Post by Alasdair G Kergon
Let's stop there. The fact you're asking a question about setuid
suggests you don't understand enough to be able to use it safely.
I get security by checking the real user id at the beginning of the
program and aborting the program if that uid does not belong to the only
user who is allowed to run the program. That user is me and I guess that
it is much more insecure to run the whole service that wants to
authenticate users through PAM as root.
Post by Alasdair G Kergon
Go back to the beginning and describe the original problem you are
trying to solve and the constraints you have and ask for advice about
ways to achieve it.
The beginning is that I want to create a user-specific logical volume
when a user logs in to a service that authenticates its users through
pam and that does not run as root.

Regards
Christoph
Zdenek Kabelac
2018-11-16 15:32:17 UTC
Permalink
This post might be inappropriate. Click to display it.
Christoph Pleger
2018-11-16 16:12:41 UTC
Permalink
Hello,
Post by Zdenek Kabelac
How do you plan to 'authorize' passed command line options ??
My program has no command line options. It just takes PAM_USER from PAM
environment and creates a logical volume /dev/vg1/$PAM_USER, creates a
filesystem and changes directory permissions of the top directory of the
new filesystem.
Post by Zdenek Kabelac
lvm2 is designed to be always executed with root privileges - so it's
believed admin knows how he can destroy his own system.
It is NOT designed/supposed to be used as suid binary - this would
give user a way to big power to very easily destroy your filesystem
and gain root privileges (i.e.by overwriting /etc/passwd file)
Either you misunderstood what I mean, or I am misunderstanding what you
mean - I do not set lvcreate suid root, but a program that has only a
small and well defined set of instructions (described above) and that
restricts its execution to only one user (by checking the real uid
before setuid(0)).

Regards
Christoph
Roger Heflin
2018-11-16 17:21:21 UTC
Permalink
Why aren't you just using sudo for this?
On Fri, Nov 16, 2018 at 11:14 AM Christoph Pleger
Post by Christoph Pleger
Hello,
Post by Zdenek Kabelac
How do you plan to 'authorize' passed command line options ??
My program has no command line options. It just takes PAM_USER from PAM
environment and creates a logical volume /dev/vg1/$PAM_USER, creates a
filesystem and changes directory permissions of the top directory of the
new filesystem.
Post by Zdenek Kabelac
lvm2 is designed to be always executed with root privileges - so it's
believed admin knows how he can destroy his own system.
It is NOT designed/supposed to be used as suid binary - this would
give user a way to big power to very easily destroy your filesystem
and gain root privileges (i.e.by overwriting /etc/passwd file)
Either you misunderstood what I mean, or I am misunderstanding what you
mean - I do not set lvcreate suid root, but a program that has only a
small and well defined set of instructions (described above) and that
restricts its execution to only one user (by checking the real uid
before setuid(0)).
Regards
Christoph
_______________________________________________
linux-lvm mailing list
https://www.redhat.com/mailman/listinfo/linux-lvm
read the LVM HOW-TO at http://tldp.org/HOWTO/LVM-HOWTO/
Alasdair G Kergon
2018-11-17 00:24:05 UTC
Permalink
This post might be inappropriate. Click to display it.
Christoph Pleger
2018-11-19 08:55:07 UTC
Permalink
Hello,
Post by Alasdair G Kergon
Post by Christoph Pleger
I get security by checking the real user id at the beginning of the
program and aborting the program if that uid does not belong to the only
user who is allowed to run the program.
Sounds familiar. Shall I tell you one of those stories?
...
...
...
My program calls getpwuid() with the real user id of the calling user
and then compares this user's name with the name of the one and only
user who is allowed to continue program execution. Do you think that
this can be circumvented?

Regards
Christoph
Alasdair G Kergon
2018-11-19 13:01:50 UTC
Permalink
Post by Christoph Pleger
My program calls getpwuid() with the real user id of the calling user
and then compares this user's name with the name of the one and only
user who is allowed to continue program execution. Do you think that
this can be circumvented?
I'll just repeat - don't write your own setuid programs if you care
about security. Here's an old paper that lists some (and certainly not
all!) of the things people who do write them have to understand:

http://man7.org/conf/lca2010/writing_secure_privileged_programs.pdf

It only takes one mistake or one thing you didn't know about or
understand properly to make your system insecure.

Alasdair
Bryn M. Reeves
2018-11-19 13:19:40 UTC
Permalink
Post by Christoph Pleger
The beginning is that I want to create a user-specific logical volume when a
user logs in to a service that authenticates its users through pam and that
does not run as root.
Couldn't you use a pam_scripts ses_open/ses_close hook to do this?

That way you can get rid of any suid binary and rely on the well
tested PAM stack to carry out the set up (and optionally clean up)
for the users at login/out time.

Regards,
Bryn.
Christoph Pleger
2018-11-19 15:17:18 UTC
Permalink
Hello,
Post by Bryn M. Reeves
Post by Christoph Pleger
The beginning is that I want to create a user-specific logical volume when a
user logs in to a service that authenticates its users through pam and that
does not run as root.
Couldn't you use a pam_scripts ses_open/ses_close hook to do this?
That way you can get rid of any suid binary and rely on the well
tested PAM stack to carry out the set up (and optionally clean up)
for the users at login/out time.
Hm, I do not see how the scripts called by pam_scripts can be executed
with another user id than the process that called pam_authenticate()?

Regards
Christoph
Stuart D. Gathman
2018-11-16 15:41:53 UTC
Permalink
It's not very elegant, but the quick and dirty solution is to use sudo
to allow certain users to run specific commands with a real uid of
root. You can say exactly what arguments the user has to use - the
sudoers file is where this is configured. Or you can make a script -
which is probably better. But said script should have no arguments, or
as few as possible - because any complexity allows that user to attempt
to exploit it to acheive root. Such a script could trivially bring a
specific LV online, writable by a specific user. More complex
requirement would be - more complex.

If LVM has more elegant features for this kind of thing, I'm all ears.

On Fri, Nov 16, 2018 at 8:43 AM, Christoph Pleger
Post by Christoph Pleger
Post by Alasdair G Kergon
Go back to the beginning and describe the original problem you are
trying to solve and the constraints you have and ask for advice about
ways to achieve it.
The beginning is that I want to create a user-specific logical volume
when a user logs in to a service that authenticates its users through
pam and that does not run as root.
Regards
Christoph
Christoph Pleger
2018-11-21 09:56:58 UTC
Permalink
Hello,
Post by Stuart D. Gathman
It's not very elegant, but the quick and dirty solution is to use sudo
probably you had not yet read that far in this thread, but I already
wrote that sudo does not work when called from pam_exec.

To get the stderr and stdout results of sudo, I wrote a shell script
wrapper around it, and the results are (maybe because sudo itself uses
PAM?):

sudo: unable to change to root gid: Operation not permitted
sudo: unable to initialize policy plugin

Someone wrote that he assumes that pam_exec ignores the setuid-bit in
the file permissions, but that is obviously wrong, as this whole thread
is about why lvcreate, when being called from my setuid-root-binary, has
permission problems though all three (real, effective and saved) UIDs
are 0 (and of course I checked that they really are 0).

Regards
Christoph
Vladislav Bogdanov
2018-11-21 09:58:50 UTC
Permalink
Post by Christoph Pleger
Hello,
Post by Stuart D. Gathman
It's not very elegant, but the quick and dirty solution is to use sudo
probably you had not yet read that far in this thread, but I already
wrote that sudo does not work when called from pam_exec.
To get the stderr and stdout results of sudo, I wrote a shell script
wrapper around it, and the results are (maybe because sudo itself uses
sudo: unable to change to root gid: Operation not permitted
sudo: unable to initialize policy plugin
May be silly question: Do you have selinux or equivalent enabled?
Post by Christoph Pleger
Someone wrote that he assumes that pam_exec ignores the setuid-bit in
the file permissions, but that is obviously wrong, as this whole thread
is about why lvcreate, when being called from my setuid-root-binary, has
permission problems though all three (real, effective and saved) UIDs
are 0 (and of course I checked that they really are 0).
Regards
  Christoph
_______________________________________________
linux-lvm mailing list
https://www.redhat.com/mailman/listinfo/linux-lvm
read the LVM HOW-TO at http://tldp.org/HOWTO/LVM-HOWTO/
Christoph Pleger
2018-11-21 10:23:23 UTC
Permalink
Hello,
Post by Vladislav Bogdanov
May be silly question: Do you have selinux or equivalent enabled?
I HAD apparmor enabled, but after the first failures (like described
here) had occurred, I also suspected apparmor as a possible reason and
disabled it. Unfortunately, that did not help.

Regards
Christoph
matthew patton
2018-11-19 14:04:46 UTC
Permalink
Post by Christoph Pleger
program calls getpwuid() with the real user id of the calling user
maybe I missed a critical post explaining why it has to be, but that's a job for a trivial sudo specification line.

I can't think of any reason why sudo is not the answer to your problem, or frankly isn't always the answer.
Christoph Pleger
2018-11-19 15:03:53 UTC
Permalink
Hello,
Post by matthew patton
Post by Christoph Pleger
program calls getpwuid() with the real user id of the calling user
maybe I missed a critical post explaining why it has to be, but that's
a job for a trivial sudo specification line.
I can't think of any reason why sudo is not the answer to your
problem, or frankly isn't always the answer.
I have already tried sudo before writing my own setuid-root-program, by
calling it directly from pam_exec and by letting pam_exec call another
program first that calls sudo. Either case failed, even with simple
tests like letting sudo run /bin/ls (and of course I checked before that
the same user could use sudo from the command line).

Regards
Christoph
Christoph Pleger
2018-11-19 15:35:40 UTC
Permalink
Hello,
Post by Christoph Pleger
Unfortunately - though these UIDs are all set to 0 - lvcreate still
does not work for me. That is, it does work when I call my
setuid-binary as a non-root user from the command line, but it does
not work when I call my setuid-binary from PAM module pam_exec - and
that is what I need my program for. I let my program send lvcreate
device-mapper: version ioctl on failed: Permission denied
Incompatible libdevmapper 1.02.137 (2016-11-30) and kernel driver
(unknown version).
striped: Required device-mapper target(s) not detected in your kernel.
Run `lvcreate --help' for more information.
What might be the problem here so that lvcreate gives these errors
though all UIDs are 0?
No matter if I use that setuid-mechanism in the end or not, I would
still like to know why it does not work as-is with lvcreate. :-)

I guess that the error message "device-mapper: version ioctl on failed:
Permission denied" comes from the following lines in LVM's
libdm/ioctl/libdm-iface.c:


if (_log_suppress || dmt->ioctl_errno == EINTR)
log_verbose("device-mapper: %s ioctl on %s%s%s%.0d%s%.0d%s%s "
"failed: %s",
_cmd_data_v4[dmt->type].name,
dmi->name, dmi->uuid,
dmt->major > 0 ? "(" : "",
dmt->major > 0 ? dmt->major : 0,
dmt->major > 0 ? ":" : "",
dmt->minor > 0 ? dmt->minor : 0,
dmt->major > 0 && dmt->minor == 0 ? "0" : "",
dmt->major > 0 ? ")" : "",
strerror(dmt->ioctl_errno));
else
log_error("device-mapper: %s ioctl on %s%s%s%.0d%s%.0d%s%s "
"failed: %s",
_cmd_data_v4[dmt->type].name,
dmi->name, dmi->uuid,
dmt->major > 0 ? "(" : "",
dmt->major > 0 ? dmt->major : 0,
dmt->major > 0 ? ":" : "",
dmt->minor > 0 ? dmt->minor : 0,
dmt->major > 0 && dmt->minor == 0 ? "0" : "",
dmt->major > 0 ? ")" : "",
strerror(dmt->ioctl_errno));

But somehow, the values are empty ...

Regards
Christoph
matthew patton
2018-11-19 16:05:14 UTC
Permalink
http://linux-pam.org/Linux-PAM-html/sag-pam_exec.html

I would further assume pam_exec ignores SUID bit on binaries either because of a bug or deliberately because there is no good reason to ever do that.
matthew patton
2018-11-22 16:41:23 UTC
Permalink
assuming you haven't seen this.
https://stackoverflow.com/questions/14655929/pam-exec-and-security
Loading...