summaryrefslogtreecommitdiffstats
path: root/usr.sbin/rpc.lockd
diff options
context:
space:
mode:
authoralfred <alfred@FreeBSD.org>2001-10-14 18:36:35 +0000
committeralfred <alfred@FreeBSD.org>2001-10-14 18:36:35 +0000
commit8dd54dc1741b2f7b46d6ced09abf391310734eec (patch)
tree40f80a0f57dfb0dfb2290567405905c0f3ac7fb3 /usr.sbin/rpc.lockd
parent6a3c586dafc5a7e779887897918ced79205d20ca (diff)
downloadFreeBSD-src-8dd54dc1741b2f7b46d6ced09abf391310734eec.zip
FreeBSD-src-8dd54dc1741b2f7b46d6ced09abf391310734eec.tar.gz
Implement partial-file NFS lock testing.
Submitted by: "Andrew P. Lentvorski" <andrewl@io.com>
Diffstat (limited to 'usr.sbin/rpc.lockd')
-rw-r--r--usr.sbin/rpc.lockd/lock_proc.c74
-rw-r--r--usr.sbin/rpc.lockd/lockd_lock.c76
-rw-r--r--usr.sbin/rpc.lockd/lockd_lock.h2
3 files changed, 139 insertions, 13 deletions
diff --git a/usr.sbin/rpc.lockd/lock_proc.c b/usr.sbin/rpc.lockd/lock_proc.c
index 389baf6..ad7106c 100644
--- a/usr.sbin/rpc.lockd/lock_proc.c
+++ b/usr.sbin/rpc.lockd/lock_proc.c
@@ -87,6 +87,40 @@ log_from_addr(fun_name, req)
syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
}
+/* log_netobj ----------------------------------------------------------- */
+/*
+ * Purpose: Log a netobj
+ * Returns: Nothing
+ * Notes: This function should only really be called as part of
+ * a debug subsystem.
+*/
+static void
+log_netobj(obj)
+ netobj *obj;
+{
+ char objvalbuffer[(sizeof(char)*2)*MAX_NETOBJ_SZ+2];
+ char objascbuffer[sizeof(char)*MAX_NETOBJ_SZ+1];
+ int i, maxlen;
+ char *tmp1, *tmp2;
+
+ /* Notify of potential security attacks */
+ if (obj->n_len > MAX_NETOBJ_SZ) {
+ syslog(LOG_DEBUG, "SOMEONE IS TRYING TO DO SOMETHING NASTY!\n");
+ syslog(LOG_DEBUG, "netobj too large! Should be %d was %d\n",
+ MAX_NETOBJ_SZ, obj->n_len);
+ }
+ /* Prevent the security hazard from the buffer overflow */
+ maxlen = (obj->n_len < MAX_NETOBJ_SZ ? obj->n_len : MAX_NETOBJ_SZ);
+ for (i=0, tmp1 = objvalbuffer, tmp2 = objascbuffer; i < obj->n_len;
+ i++, tmp1 +=2, tmp2 +=1) {
+ sprintf(tmp1,"%02X",*(obj->n_bytes+i));
+ sprintf(tmp2,"%c",*(obj->n_bytes+i));
+ }
+ *tmp1 = '\0';
+ *tmp2 = '\0';
+ syslog(LOG_DEBUG,"netobjvals: %s\n",objvalbuffer);
+ syslog(LOG_DEBUG,"netobjascs: %s\n",objascbuffer);
+}
/* get_client -------------------------------------------------------------- */
/*
* Purpose: Get a CLIENT* for making RPC calls to lockd on given host
@@ -382,7 +416,7 @@ nlm_test_1_svc(arg, rqstp)
if (debug_level)
log_from_addr("nlm_test", rqstp);
- holder = testlock(&arg4, 0);
+ holder = testlock(&arg4, arg->exclusive, 0);
/*
* Copy the cookie from the argument into the result. Note that this
* is slightly hazardous, as the structure contains a pointer to a
@@ -422,7 +456,7 @@ nlm_test_msg_1_svc(arg, rqstp)
if (debug_level)
log_from_addr("nlm_test_msg", rqstp);
- holder = testlock(&arg4, 0);
+ holder = testlock(&arg4, arg->exclusive, 0);
res.cookie = arg->cookie;
if (holder == NULL) {
@@ -867,8 +901,23 @@ nlm4_test_4_svc(arg, rqstp)
if (debug_level)
log_from_addr("nlm4_test", rqstp);
+ if (debug_level > 5) {
+ syslog(LOG_DEBUG, "Locking arguments:\n");
+ log_netobj(&(arg->cookie));
+ syslog(LOG_DEBUG, "Alock arguments:\n");
+ syslog(LOG_DEBUG, "Caller Name: %s\n",arg->alock.caller_name);
+ syslog(LOG_DEBUG, "File Handle:\n");
+ log_netobj(&(arg->alock.fh));
+ syslog(LOG_DEBUG, "Owner Handle:\n");
+ log_netobj(&(arg->alock.oh));
+ syslog(LOG_DEBUG, "SVID: %d\n", arg->alock.svid);
+ syslog(LOG_DEBUG, "Lock Offset: %d\n", arg->alock.l_offset);
+ syslog(LOG_DEBUG, "Lock Length: %d\n", arg->alock.l_len);
+ syslog(LOG_DEBUG, "Exclusive: %s\n",
+ (arg->exclusive ? "true" : "false"));
+ }
- holder = testlock(&arg->alock, LOCK_V4);
+ holder = testlock(&arg->alock, arg->exclusive, LOCK_V4);
/*
* Copy the cookie from the argument into the result. Note that this
@@ -904,7 +953,7 @@ nlm4_test_msg_4_svc(arg, rqstp)
if (debug_level)
log_from_addr("nlm4_test_msg", rqstp);
- holder = testlock(&arg->alock, LOCK_V4);
+ holder = testlock(&arg->alock, arg->exclusive, LOCK_V4);
res.cookie = arg->cookie;
if (holder == NULL) {
@@ -948,6 +997,23 @@ nlm4_lock_4_svc(arg, rqstp)
if (debug_level)
log_from_addr("nlm4_lock", rqstp);
+ if (debug_level > 5) {
+ syslog(LOG_DEBUG, "Locking arguments:\n");
+ log_netobj(&(arg->cookie));
+ syslog(LOG_DEBUG, "Alock arguments:\n");
+ syslog(LOG_DEBUG, "Caller Name: %s\n",arg->alock.caller_name);
+ syslog(LOG_DEBUG, "File Handle:\n");
+ log_netobj(&(arg->alock.fh));
+ syslog(LOG_DEBUG, "Owner Handle:\n");
+ log_netobj(&(arg->alock.oh));
+ syslog(LOG_DEBUG, "SVID: %d\n", arg->alock.svid);
+ syslog(LOG_DEBUG, "Lock Offset: %d\n", arg->alock.l_offset);
+ syslog(LOG_DEBUG, "Lock Length: %d\n", arg->alock.l_len);
+ syslog(LOG_DEBUG, "Block: %s\n", (arg->block ? "true" : "false"));
+ syslog(LOG_DEBUG, "Exclusive: %s\n", (arg->exclusive ? "true" : "false"));
+ syslog(LOG_DEBUG, "Reclaim: %s\n", (arg->reclaim ? "true" : "false"));
+ syslog(LOG_DEBUG, "State num: %d\n", arg->state);
+ }
/* copy cookie from arg to result. See comment in nlm_test_4() */
res.cookie = arg->cookie;
diff --git a/usr.sbin/rpc.lockd/lockd_lock.c b/usr.sbin/rpc.lockd/lockd_lock.c
index 7a6c00d..19c38a7 100644
--- a/usr.sbin/rpc.lockd/lockd_lock.c
+++ b/usr.sbin/rpc.lockd/lockd_lock.c
@@ -54,7 +54,12 @@
#include "lockd_lock.h"
#include "lockd.h"
-/* A set of utilities for managing file locking */
+/*
+ * A set of utilities for managing file locking
+ *
+ * XXX: All locks are in a linked list, a better structure should be used
+ * to improve search/access effeciency.
+ */
LIST_HEAD(lcklst_head, file_lock);
struct lcklst_head lcklst_head = LIST_HEAD_INITIALIZER(lcklst_head);
@@ -75,6 +80,7 @@ struct file_lock {
/* lock status */
#define LKST_LOCKED 1 /* lock is locked */
+/* XXX: Is this flag file specific or lock specific? */
#define LKST_WAITING 2 /* file is already locked by another host */
#define LKST_PROCESSING 3 /* child is trying to aquire the lock */
#define LKST_DYING 4 /* must dies when we get news from the child */
@@ -85,6 +91,8 @@ enum nlm_stats do_unlock __P((struct file_lock *));
void send_granted __P((struct file_lock *, int));
void siglock __P((void));
void sigunlock __P((void));
+int regions_overlap __P((u_int64_t start1, u_int64_t len1, u_int64_t start2,
+ u_int64_t len2));
/* list of hosts we monitor */
LIST_HEAD(hostlst_head, host);
@@ -100,14 +108,44 @@ struct host {
void do_mon __P((char *));
/*
+ * regions_overlap(): This function examines the two provided regions for overlap.
+ * It is non-trivial because start+len *CAN* overflow a 64-bit unsigned integer
+ * and NFS semantics are unspecified on this account.
+ */
+int
+regions_overlap(start1, len1, start2, len2)
+ u_int64_t start1, len1, start2, len2;
+{
+ int result;
+
+ /* XXX: Need to adjust checks to account for integer overflow */
+ if (len1 == 0 && len2 == 0) {
+ /* Regions *must* overlap if they both extend to the end */
+ result = TRUE;
+ } else if (len1 == 0 && start2+len2 < start1) {
+ /* Region 2 is completely to the left of Region 1 */
+ result = FALSE;
+ } else if (start1+len1 < start2 && len2 == 0) {
+ /* Region 1 is completely to the left of region 2 */
+ result = FALSE;
+ } else if (start1 + len1 <= start2 || start2+len2 <= start1) {
+ /* 1 is completely left of 2 or 2 is completely left of 1 */
+ result = FALSE;
+ } else {
+ result = TRUE;
+ }
+ return (result);
+}
+/*
* testlock(): inform the caller if the requested lock would be granted or not
* returns NULL if lock would granted, or pointer to the current nlm4_holder
* otherwise.
*/
struct nlm4_holder *
-testlock(lock, flags)
+testlock(lock, exclusive, flags)
struct nlm4_lock *lock;
+ bool_t exclusive;
int flags;
{
struct file_lock *fl;
@@ -122,18 +160,40 @@ testlock(lock, flags)
fl = LIST_NEXT(fl, lcklst)) {
if (fl->status != LKST_LOCKED)
continue;
+ /*
+ * XXX: Could we possibly have identical filehandles
+ * on different systems?
+ * ie. Do we need to check more than just the filehandle?
+ * ie. Could someone artificially create requests which are
+ * security violations?
+ */
if (memcmp(&fl->filehandle, &filehandle, sizeof(filehandle)))
continue;
- /* got it ! */
+ /* File handles match, look for lock region overlap */
+ if (regions_overlap(lock->l_offset, lock->l_len,
+ fl->client.l_offset, fl->client.l_len)) {
+ syslog(LOG_DEBUG,
+ "Region overlap found %llu : %llu -- %llu : %llu\n",
+ lock->l_offset, lock->l_len,
+ fl->client.l_offset,fl->client.l_len);
+ /* Regions overlap. Now check for exclusivity. */
+ if (exclusive || fl->client.exclusive) {
+ /* Lock test must fail, regions are exclusive */
+ break;
+ }
+ }
+ /* Continue looping through all locks */
+ }
+ sigunlock();
+ if (fl == NULL) {
+ syslog(LOG_DEBUG, "test for %s: no lock found",
+ lock->caller_name);
+ return NULL;
+ } else {
syslog(LOG_DEBUG, "test for %s: found lock held by %s",
lock->caller_name, fl->client_name);
- sigunlock();
return (&fl->client);
}
- /* not found */
- sigunlock();
- syslog(LOG_DEBUG, "test for %s: no lock found", lock->caller_name);
- return NULL;
}
/*
diff --git a/usr.sbin/rpc.lockd/lockd_lock.h b/usr.sbin/rpc.lockd/lockd_lock.h
index 5b0232f..bcd9b6f 100644
--- a/usr.sbin/rpc.lockd/lockd_lock.h
+++ b/usr.sbin/rpc.lockd/lockd_lock.h
@@ -3,7 +3,7 @@
/* Headers and function declarations for file-locking utilities */
-struct nlm4_holder * testlock __P((struct nlm4_lock *, int));
+struct nlm4_holder * testlock __P((struct nlm4_lock *, int, int));
enum nlm_stats getlock __P((nlm4_lockargs *, struct svc_req *, int));
enum nlm_stats unlock __P((nlm4_lock *, int));
OpenPOWER on IntegriCloud