Implement partial-file NFS lock testing.

Submitted by: "Andrew P. Lentvorski" <andrewl@io.com>
This commit is contained in:
Alfred Perlstein 2001-10-14 18:36:35 +00:00
parent a387081c63
commit bad584e319
3 changed files with 139 additions and 13 deletions

View File

@ -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;

View File

@ -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);
@ -99,6 +107,35 @@ 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
@ -106,8 +143,9 @@ void do_mon __P((char *));
*/
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;
}
/*

View File

@ -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));