What factors affect whether an NTFS partition can be mounted by a user on Linux?

I have two Win8-made NTFS partitions on my system. Running Debian testing, Linux kernel 3.16, I can mount one of them as a regular user, but trying to mount the other one results in an error:

$ mount /media/WinC
Error opening '/dev/sda1': Permission denied
Failed to mount '/dev/sda1': Permission denied
Please check '/dev/sda1' and the ntfs-3g binary permissions,
and the mounting user ID. More explanation is provided at
http://tuxera.com/community/ntfs-3g-faq/#unprivileged

Both can be mounted by root, resulting in identical entries in /etc/mtab:

/dev/sda1 /media/WinC fuseblk rw,nosuid,nodev,noexec,relatime,user_id=0,group_id=0,allow_other,blksize=4096 0 0
/dev/sdb6 /media/WinE fuseblk rw,nosuid,nodev,noexec,relatime,user_id=0,group_id=0,allow_other,blksize=4096 0 0

Entries in /etc/fstab for both are identical:

/dev/sda1  /media/WinC  ntfs-3g  rw,user,noauto  0  0
/dev/sdb6  /media/WinE  ntfs-3g  rw,user,noauto  0  0

Access rights to the mount points are identical:

drwxr-xr-x  2 root root 4096 Jan 25  2013 WinC/
drwxr-xr-x  2 root root 4096 Nov 27 22:58 WinE/

And finally, access rights to the block devices are identical:

brw-rw---- 1 root disk 8,  1 Dec 10 20:17 /dev/sda1
brw-rw---- 1 root disk 8, 22 Dec 10 16:24 /dev/sdb6

So, what's the factor that makes mounting-as-user for one of them work and for the other fail?


Following the request of podwysoc, here is the output of strace ntfs-3g /dev/sda1 /media/WinC:

execve("/bin/ntfs-3g", ["ntfs-3g", "/dev/sda1", "/media/WinC"], [/* 45 vars */]) = 0
brk(0)                                  = 0x7fe6bbca8000
fcntl(0, F_GETFD)                       = 0
fcntl(1, F_GETFD)                       = 0
fcntl(2, F_GETFD)                       = 0
access("/etc/suid-debug", F_OK)         = -1 ENOENT (No such file or directory)
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe6bb8b9000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=157945, ...}) = 0
mmap(NULL, 157945, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe6bb892000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20o\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=137440, ...}) = 0
mmap(NULL, 2213008, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe6bb47e000
mprotect(0x7fe6bb496000, 2093056, PROT_NONE) = 0
mmap(0x7fe6bb695000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17000) = 0x7fe6bb695000
mmap(0x7fe6bb697000, 13456, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fe6bb697000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libntfs-3g.so.852", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\216\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=334248, ...}) = 0
mmap(NULL, 2429528, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe6bb22c000
mprotect(0x7fe6bb27c000, 2097152, PROT_NONE) = 0
mmap(0x7fe6bb47c000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x50000) = 0x7fe6bb47c000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\34\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1729984, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe6bb891000
mmap(NULL, 3836448, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe6bae83000
mprotect(0x7fe6bb022000, 2097152, PROT_NONE) = 0
mmap(0x7fe6bb222000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19f000) = 0x7fe6bb222000
mmap(0x7fe6bb228000, 14880, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fe6bb228000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe6bb890000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe6bb88f000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe6bb88e000
arch_prctl(ARCH_SET_FS, 0x7fe6bb88f700) = 0
mprotect(0x7fe6bb222000, 16384, PROT_READ) = 0
mprotect(0x7fe6bb47c000, 4096, PROT_READ) = 0
mprotect(0x7fe6bb695000, 4096, PROT_READ) = 0
mprotect(0x7fe6bbadf000, 8192, PROT_READ) = 0
mprotect(0x7fe6bb8bb000, 4096, PROT_READ) = 0
munmap(0x7fe6bb892000, 157945)          = 0
set_tid_address(0x7fe6bb88f9d0)         = 8822
set_robust_list(0x7fe6bb88f9e0, 24)     = 0
rt_sigaction(SIGRTMIN, {0x7fe6bb4849f0, [], SA_RESTORER|SA_SIGINFO, 0x7fe6bb48d8d0}, NULL, 8) = 0
rt_sigaction(SIGRT_1, {0x7fe6bb484a80, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x7fe6bb48d8d0}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
open("/dev/null", O_RDWR)               = 3
close(3)                                = 0
getegid()                               = 1000
geteuid()                               = 1000
brk(0)                                  = 0x7fe6bbca8000
brk(0x7fe6bbcc9000)                     = 0x7fe6bbcc9000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1613360, ...}) = 0
mmap(NULL, 1613360, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe6bb704000
close(3)                                = 0
lstat("/dev", {st_mode=S_IFDIR|0755, st_size=3700, ...}) = 0
lstat("/dev/sda1", {st_mode=S_IFBLK|0660, st_rdev=makedev(8, 1), ...}) = 0
getuid()                                = 1000
getgid()                                = 1000
lstat("/dev", {st_mode=S_IFDIR|0755, st_size=3700, ...}) = 0
lstat("/dev/sda1", {st_mode=S_IFBLK|0660, st_rdev=makedev(8, 1), ...}) = 0
open("/proc/mounts", O_RDONLY|O_CLOEXEC) = 3
futex(0x7fe6bb229088, FUTEX_WAKE_PRIVATE, 2147483647) = 0
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe6bb8b8000
read(3, "rootfs / rootfs rw 0 0\nsysfs /sy"..., 1024) = 1024
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/rootfs", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/sysfs", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/proc", 0x7fffdd24c640)  = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/udev", 0x7fffdd24c640)  = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/devpts", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/tmpfs", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
lstat("/dev", {st_mode=S_IFDIR|0755, st_size=3700, ...}) = 0
lstat("/dev/disk", {st_mode=S_IFDIR|0755, st_size=140, ...}) = 0
lstat("/dev/disk/by-uuid", {st_mode=S_IFDIR|0755, st_size=200, ...}) = 0
lstat("/dev/disk/by-uuid/f522a1c8-076e-451a-8204-846884bbd509", {st_mode=S_IFLNK|0777, st_size=10, ...}) = 0
readlink("/dev/disk/by-uuid/f522a1c8-076e-451a-8204-846884bbd509", "../../sda2", 4095) = 10
lstat("/dev/sda2", {st_mode=S_IFBLK|0660, st_rdev=makedev(8, 2), ...}) = 0
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/securityfs", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/tmpfs", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/tmpfs", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/tmpfs", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/cgroup", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/pstore", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/cgroup", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
read(3, "/cgroup/cpu,cpuacct cgroup rw,no"..., 1024) = 1024
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/cgroup", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/cgroup", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/cgroup", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/cgroup", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/cgroup", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/cgroup", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/systemd-1", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/mqueue", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/debugfs", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/hugetlbfs", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/fusectl", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/tmpfs", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
lstat("/dev", {st_mode=S_IFDIR|0755, st_size=3700, ...}) = 0
lstat("/dev/sdb3", {st_mode=S_IFBLK|0660, st_rdev=makedev(8, 19), ...}) = 0
lstat("/dev", {st_mode=S_IFDIR|0755, st_size=3700, ...}) = 0
lstat("/dev/sdb2", {st_mode=S_IFBLK|0660, st_rdev=makedev(8, 18), ...}) = 0
read(3, "rdered 0 0\n/dev/sdb4 /home/ca/St"..., 1024) = 221
lstat("/dev", {st_mode=S_IFDIR|0755, st_size=3700, ...}) = 0
lstat("/dev/sdb5", {st_mode=S_IFBLK|0660, st_rdev=makedev(8, 21), ...}) = 0
lstat("/dev", {st_mode=S_IFDIR|0755, st_size=3700, ...}) = 0
lstat("/dev/sdb4", {st_mode=S_IFBLK|0660, st_rdev=makedev(8, 20), ...}) = 0
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/rpc_pipefs", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
getcwd("/home/ca", 4096)                = 9
lstat("/home/ca/tmpfs", 0x7fffdd24c640) = -1 ENOENT (No such file or directory)
read(3, "", 1024)                       = 0
close(3)                                = 0
munmap(0x7fe6bb8b8000, 4096)            = 0
stat("/media/WinC", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("/proc/filesystems", O_RDONLY)     = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe6bb8b8000
read(3, "nodev\tsysfs\nnodev\trootfs\nnodev\tr"..., 1024) = 338
close(3)                                = 0
munmap(0x7fe6bb8b8000, 4096)            = 0
geteuid()                               = 1000
getresuid([1000], [1000], [1000])       = 0
setresuid(4294967295, 1000, 4294967295) = 0
geteuid()                               = 1000
getegid()                               = 1000
getresgid([1000], [1000], [1000])       = 0
setresgid(4294967295, 1000, 4294967295) = 0
getegid()                               = 1000
stat("/dev/fuse", {st_mode=S_IFCHR|0666, st_rdev=makedev(10, 229), ...}) = 0
getegid()                               = 1000
geteuid()                               = 1000
stat("/dev/sda1", {st_mode=S_IFBLK|0660, st_rdev=makedev(8, 1), ...}) = 0
mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe6bb898000
stat("/dev/sda1", {st_mode=S_IFBLK|0660, st_rdev=makedev(8, 1), ...}) = 0
open("/dev/sda1", O_RDWR)               = -1 EACCES (Permission denied)
write(2, "Error opening '/dev/sda1'", 25Error opening '/dev/sda1') = 25
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2492, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe6bb897000
read(3, "# Locale name alias data base.\n#"..., 4096) = 2492
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7fe6bb897000, 4096)            = 0
open("/usr/share/locale/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, ": Permission denied\n", 20: Permission denied
)   = 20
munmap(0x7fe6bb898000, 135168)          = 0
write(2, "Failed to mount '/dev/sda1'", 27Failed to mount '/dev/sda1') = 27
write(2, ": Permission denied\n", 20: Permission denied
)   = 20
write(2, "Please check '/dev/sda1' and the"..., 173Please check '/dev/sda1' and the ntfs-3g binary permissions,
and the mounting user ID. More explanation is provided at
http://tuxera.com/community/ntfs-3g-faq/#unprivileged
) = 173
exit_group(19)                          = ?
+++ exited with 19 +++

The link mentioned in the error may hold the answer. The relevant sections:

Why have chmod and chown no effect?

By default files on NTFS are owned by root with full access to everyone. To get standard per-file protection you should mount with the “permissions” option. Moreover, if you want the permissions to be interoperable with a specific Windows configuration, you have to map the users.

Why can’t unprivileged users mount block devices?
or
Why do I get “fusermount: option blkdev is privileged” error?

Unprivileged block device mounts work only if all the below requirements are met:

  1. ntfs-3g is compiled with integrated FUSE support
  2. the ntfs-3g binary is at least version 1.2506
  3. the ntfs-3g binary is set to setuid-root
  4. the user has access right to the volume
  5. the user has access right to the mount point

The root user can make an ntfs-3g binary setuid-root as shown below

chown root $(which ntfs-3g)
chmod 4755 $(which ntfs-3g)

In such case the driver will also be able

  • to fix common FUSE kernel module loading problems
  • to create the required but sometimes incorrectly removed or missing FUSE device file

Please note that using setuid-root can result unforeseen privilege escalation and its usage is discouraged. Only the absolutely trusted users must be granted such access. Below is an example how this can be done for users in the ntfsuser group to be able to mount any NTFS volume if they have also the needed volume access rights.

chown root.ntfsuser $(which ntfs-3g)
chmod 4750 $(which ntfs-3g)

The setuid-root ntfs-3g driver applies the principle of least privilege during its lifetime as a safety measure.

Why don’t the ‘user’ and ‘users’ options work in /etc/fstab?

The ‘mount’ command doesn’t invoke the ntfs-3g binary with the needed privilege after it has checked and approved the user is entitled to mount a given device on a specified mount point, hereby the user can’t open the device he got the approval in /etc/fstab. This is a problem in the ‘mount’ utility.

Solution: Use at least NTFS-3G 1.2506 with setuid-root set and make sure the user has access rights to the volume and mount point.

There are two facets to this question:

  • How to give regular users access to the NTFS partitions
  • Scientific curiosity about why the two partitions behave differently

There are no obvious differences between the partitions. The link talks about a problem with the mount utility (and a solution). There may be other things going on, such as udev activity, complicating the situation. As I read the link, it appears that the question should actually be why one partition does mount as a regular user since mount and fstab should work only for root. Answering the second part of the question is likely to be a detective and guessing game, and I can't help with that part given the available information.

However, the first part of the question appears to have a solution. According to the link, the partitions must be mounted as root, and according to the question, this works. Regular user access is accomplished through permissions, as described above.