summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2010-01-26 16:51:57 -0800
committerJeremy Allison <jra@samba.org>2010-01-26 16:51:57 -0800
commit899bd0005f56dcc1e95c3988d41ab3f628bb15db (patch)
tree633dfaaf9f240a6571c49fc4da2fc7a2f0e5def9 /source3
parent2dd301e5cd6ff97943c4bf9c7cd9b820d6193b45 (diff)
downloadsamba-899bd0005f56dcc1e95c3988d41ab3f628bb15db.tar.gz
samba-899bd0005f56dcc1e95c3988d41ab3f628bb15db.tar.bz2
samba-899bd0005f56dcc1e95c3988d41ab3f628bb15db.zip
Fix bug #7067 - Linux asynchronous IO (aio) can cause smbd to fail to respond to a read or write.
Only works on Linux kernels 2.6.26 and above. Grants CAP_KILL capability to allow Linux threads under different euids to send signals to each other. Jeremy.
Diffstat (limited to 'source3')
-rw-r--r--source3/include/smb.h3
-rw-r--r--source3/lib/system.c65
-rw-r--r--source3/smbd/server.c8
3 files changed, 71 insertions, 5 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h
index bc7a90d549..041c96bada 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -1723,7 +1723,8 @@ minimum length == 24.
enum smbd_capability {
KERNEL_OPLOCK_CAPABILITY,
DMAPI_ACCESS_CAPABILITY,
- LEASE_CAPABILITY
+ LEASE_CAPABILITY,
+ KILL_CAPABILITY
};
/*
diff --git a/source3/lib/system.c b/source3/lib/system.c
index a58d9037a7..9c1da3a78b 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -883,6 +883,11 @@ char *sys_getwd(char *s)
#if defined(HAVE_POSIX_CAPABILITIES)
+/* This define hasn't made it into the glibc capabilities header yet. */
+#ifndef SECURE_NO_SETUID_FIXUP
+#define SECURE_NO_SETUID_FIXUP 2
+#endif
+
/**************************************************************************
Try and abstract process capabilities (for systems that have them).
****************************************************************************/
@@ -913,6 +918,32 @@ static bool set_process_capability(enum smbd_capability capability,
}
#endif
+#if defined(HAVE_PRCTL) && defined(PR_SET_SECUREBITS) && defined(SECURE_NO_SETUID_FIXUP)
+ /* New way of setting capabilities as "sticky". */
+
+ /*
+ * Use PR_SET_SECUREBITS to prevent setresuid()
+ * atomically dropping effective capabilities on
+ * uid change. Only available in Linux kernels
+ * 2.6.26 and above.
+ *
+ * See here:
+ * http://www.kernel.org/doc/man-pages/online/pages/man7/capabilities.7.html
+ * for details.
+ *
+ * Specifically the CAP_KILL capability we need
+ * to allow Linux threads under different euids
+ * to send signals to each other.
+ */
+
+ if (prctl(PR_SET_SECUREBITS, 1 << SECURE_NO_SETUID_FIXUP)) {
+ DEBUG(0,("set_process_capability: "
+ "prctl PR_SET_SECUREBITS failed with error %s\n",
+ strerror(errno) ));
+ return false;
+ }
+#endif
+
cap = cap_get_proc();
if (cap == NULL) {
DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
@@ -941,6 +972,11 @@ static bool set_process_capability(enum smbd_capability capability,
cap_vals[num_cap_vals++] = CAP_LEASE;
#endif
break;
+ case KILL_CAPABILITY:
+#ifdef CAP_KILL
+ cap_vals[num_cap_vals++] = CAP_KILL;
+#endif
+ break;
}
SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
@@ -950,16 +986,37 @@ static bool set_process_capability(enum smbd_capability capability,
return True;
}
- cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
- enable ? CAP_SET : CAP_CLEAR);
+ /*
+ * Ensure the capability is effective. We assume that as a root
+ * process it's always permitted.
+ */
+
+ if (cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
+ enable ? CAP_SET : CAP_CLEAR) == -1) {
+ DEBUG(0, ("set_process_capability: cap_set_flag effective "
+ "failed (%d): %s\n",
+ (int)capability,
+ strerror(errno)));
+ cap_free(cap);
+ return false;
+ }
/* We never want to pass capabilities down to our children, so make
* sure they are not inherited.
*/
- cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
+ if (cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals,
+ cap_vals, CAP_CLEAR) == -1) {
+ DEBUG(0, ("set_process_capability: cap_set_flag inheritable "
+ "failed (%d): %s\n",
+ (int)capability,
+ strerror(errno)));
+ cap_free(cap);
+ return false;
+ }
if (cap_set_proc(cap) == -1) {
- DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
+ DEBUG(0, ("set_process_capability: cap_set_flag (%d) failed: %s\n",
+ (int)capability,
strerror(errno)));
cap_free(cap);
return False;
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 09ad8d8ea5..fb0efd2ae5 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -1047,6 +1047,14 @@ extern void build_options(bool screen);
gain_root_privilege();
gain_root_group_privilege();
+ /*
+ * Ensure we have CAP_KILL capability set on Linux,
+ * where we need this to communicate with threads.
+ * This is inherited by new threads, but not by new
+ * processes across exec().
+ */
+ set_effective_capability(KILL_CAPABILITY);
+
fault_setup((void (*)(void *))exit_server_fault);
dump_core_setup("smbd");