diff options
author | alfred <alfred@FreeBSD.org> | 2001-10-14 18:36:35 +0000 |
---|---|---|
committer | alfred <alfred@FreeBSD.org> | 2001-10-14 18:36:35 +0000 |
commit | 8dd54dc1741b2f7b46d6ced09abf391310734eec (patch) | |
tree | 40f80a0f57dfb0dfb2290567405905c0f3ac7fb3 /usr.sbin/rpc.lockd | |
parent | 6a3c586dafc5a7e779887897918ced79205d20ca (diff) | |
download | FreeBSD-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.c | 74 | ||||
-rw-r--r-- | usr.sbin/rpc.lockd/lockd_lock.c | 76 | ||||
-rw-r--r-- | usr.sbin/rpc.lockd/lockd_lock.h | 2 |
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)); |