From: Markus Koschany Date: Fri, 21 Sep 2018 12:33:11 +0000 (+0200) Subject: Import Debian changes 1.6.9-2+deb8u8 X-Git-Tag: debian/1.6.9-2+deb8u8 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=61f7fa3ce2bfa23263d6247cd71e7aafa28b37e3;p=packages%2Fo%2Fopenafs.git Import Debian changes 1.6.9-2+deb8u8 openafs (1.6.9-2+deb8u8) jessie-security; urgency=high * Non-maintainer upload by the LTS team. * Fix CVE-2018-16947: The backup tape controller process accepts incoming RPCs but does not require (or allow for) authentication of those RPCs. Handling those RPCs results in operations being performed with administrator credentials, including dumping/restoring volume contents and manipulating the backup database. * Fix CVE-2018-16948: Several RPC server routines did not fully initialize their output variables before returning, leaking memory contents from both the stack and the heap. Because the OpenAFS cache manager functions as an Rx server for the AFSCB service, clients are also susceptible to information leakage. * Fix CVE-2018-16949: Several data types used as RPC input variables were implemented as unbounded array types, limited only by the inherent 32-bit length field to 4GB. An unauthenticated attacker could send, or claim to send, large input values and consume server resources waiting for those inputs, denying service to other valid connections. --- diff --git a/debian/changelog b/debian/changelog index f1e444b1b..0b470a8d8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,26 @@ +openafs (1.6.9-2+deb8u8) jessie-security; urgency=high + + * Non-maintainer upload by the LTS team. + * Fix CVE-2018-16947: + The backup tape controller process accepts incoming RPCs but does not + require (or allow for) authentication of those RPCs. Handling those RPCs + results in operations being performed with administrator credentials, + including dumping/restoring volume contents and manipulating the backup + database. + * Fix CVE-2018-16948: + Several RPC server routines did not fully initialize their output variables + before returning, leaking memory contents from both the stack and the heap. + Because the OpenAFS cache manager functions as an Rx server for the AFSCB + service, clients are also susceptible to information leakage. + * Fix CVE-2018-16949: + Several data types used as RPC input variables were implemented as + unbounded array types, limited only by the inherent 32-bit length field to + 4GB. An unauthenticated attacker could send, or claim to send, large input + values and consume server resources waiting for those inputs, denying + service to other valid connections. + + -- Markus Koschany Fri, 21 Sep 2018 14:33:11 +0200 + openafs (1.6.9-2+deb8u7) jessie; urgency=high * Apply upstream patches needed to fix kernel module build against @@ -8,10 +31,9 @@ openafs (1.6.9-2+deb8u7) jessie; urgency=high openafs (1.6.9-2+deb8u6) jessie-security; urgency=high - * CVE-2017-17432: remote triggered Rx assertion failure (Closes: #883602) + * CVE-2017-17432: remote triggered Rx assertion failure * CVE-2016-4536: information leakage from OpenAFS clients * CVE-2016-9772: information leakage from directory objects - (Closes: #846922) -- Benjamin Kaduk Fri, 08 Dec 2017 20:59:25 -0600 diff --git a/debian/patches/CVE-2018-16947.patch b/debian/patches/CVE-2018-16947.patch new file mode 100644 index 000000000..d690aa3ce --- /dev/null +++ b/debian/patches/CVE-2018-16947.patch @@ -0,0 +1,1006 @@ +From: Markus Koschany +Date: Fri, 21 Sep 2018 15:58:32 +0200 +Subject: CVE-2018-16947 + +Bug-Debian: https://bugs.debian.org/908616 +Origin: https://www.openafs.org/pages/security/openafs-sa-2018-001-stable16.patch +--- + Makefile.in | 2 +- + doc/man-pages/pod8/backup.pod | 12 +++ + doc/man-pages/pod8/butc.pod | 31 ++++++- + src/audit/audit.c | 191 +++++++++++++++++++++++++++++++++++++++++ + src/audit/audit.h | 21 +++++ + src/bucoord/bucoord_internal.h | 2 + + src/bucoord/dump.c | 34 +++++++- + src/bucoord/main.c | 5 +- + src/butc/Makefile.in | 1 + + src/butc/butc_prototypes.h | 5 ++ + src/butc/tcmain.c | 97 +++++++++++++++++---- + src/butc/tcprocs.c | 148 ++++++++++++++++++++++++++++--- + src/butc/tcstatus.c | 57 +++++++++++- + 13 files changed, 566 insertions(+), 40 deletions(-) + +diff --git a/Makefile.in b/Makefile.in +index a452b66..15ba0da 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -155,7 +155,7 @@ util: procmgmt des lwp_depinstall rx_depinstall + libafscp: util afs volser vlserver rx auth fsint + +${COMPILE_PART1} libafscp ${COMPILE_PART2} + +-audit: util rx rxkad fsint ++audit: util rx rxkad fsint bubasics + +${COMPILE_PART1} audit ${COMPILE_PART2} #TODO + + comerr: util +diff --git a/doc/man-pages/pod8/backup.pod b/doc/man-pages/pod8/backup.pod +index 3f62b25..a94d343 100644 +--- a/doc/man-pages/pod8/backup.pod ++++ b/doc/man-pages/pod8/backup.pod +@@ -188,6 +188,18 @@ interactive mode. The local identity and AFS tokens with which the + B command interpreter enters interactive mode apply to all + commands issued during the interactive session. + ++=item B<-nobutcauth> ++ ++Prior to the fix for OPENAFS-SA-2018-001, B did not allow incoming ++connections to be authenticated. As part of that fix, B was modified ++to authenticate to the B services when possible, but a B utility ++with the security fix will not interoperate with a B that lacks the fix ++unless this option is passed, which forces the use of unauthenticated ++connections to the B. Use of this option is strongly disrecommended, ++and it is provided only for backwards compatibility in environments where ++B and B communicate over a secure network environment that denies ++access to untrusted parties. ++ + =item B<-portoffset> > + + Specifies the port offset number of the Tape Coordinator that is to +diff --git a/doc/man-pages/pod8/butc.pod b/doc/man-pages/pod8/butc.pod +index 84efbf3..363b00a 100644 +--- a/doc/man-pages/pod8/butc.pod ++++ b/doc/man-pages/pod8/butc.pod +@@ -8,10 +8,14 @@ butc - Initializes the Tape Coordinator process +
+ + B S<<< [B<-port> >] >>> S<<< [B<-debuglevel> (0 | 1 | 2)] >>> +- S<<< [B<-cell> >] >>> [B<-noautoquery>] [B<-localauth>] [B<-help>] ++ S<<< [B<-cell> >] >>> [B<-noautoquery>] [B<-localauth>] ++ [B<-auditlog> > [B<-audit-interface> >]] ++ [B<-allow_unauthenticated>] [B<-help>] + + B S<<< [B<-p> >] >>> S<<< [B<-d> (0 | 1 | 2)] >>> +- S<<< [B<-c> >] >>> [B<-n>] [B<-l>] [B<-h>] ++ S<<< [B<-c> >] >>> [B<-n>] [B<-l>] ++ [B<-auditl> > [-B<-audit-i> >]] ++ [B<-al>] [B<-h>] + + =for html +
+@@ -179,6 +183,29 @@ Do not combine this argument with the B<-cell> flag, and use it only when + logged on to a server machine as the local superuser C; client + machines do not have F file. + ++=item B<-auditlog> > ++ ++Turns on audit logging, and sets the path for the audit log. The audit ++log records information about RPC calls, including the name of the RPC ++call, the host that submitted the call, the authenticated entity (user) ++that issued the call, the parameters for the call, and if the call ++succeeded or failed. ++ ++=item B<-audit-interface> <(file | sysvmq)> ++ ++Specifies what audit interface to use. Defaults to C. See ++L for an explanation of each interface. ++ ++=item B<-allow_unauthenticated> ++ ++By default the B requires clients performing TC_ RPCs to authenticate ++themselves, behavior introduced in the fix for OPENAFS-SA-2018-001. ++This option reverts to the historical behavior of only using the rxnull ++security class for incoming connections. Use of this option is strongly ++disrecommended; it is provided only for backwards compatibility with older ++clients in environments where B and B communicate over a secure ++network that denies access to untrusted parties. ++ + =item B<-help> + + Prints the online help for this command. All other valid options are +diff --git a/src/audit/audit.c b/src/audit/audit.c +index dacbef7..22a44ae 100644 +--- a/src/audit/audit.c ++++ b/src/audit/audit.c +@@ -31,6 +31,7 @@ + #include + + #include "afs/afsint.h" ++#include "afs/butc.h" + #include + #include + #include "audit.h" +@@ -152,6 +153,95 @@ audmakebuf(char *audEvent, va_list vaList) + bufferPtr += sizeof(struct AFSFid); + break; + } ++ /* butc tape label */ ++ case AUD_TLBL: ++ { ++ struct tc_tapeLabel *label; ++ ++ label = (struct tc_tapeLabel *)va_arg(vaList, ++ struct tc_tapeLabel *); ++ if (label) ++ memcpy(bufferPtr, label, sizeof(*label)); ++ else ++ memset(bufferPtr, 0, sizeof(*label)); ++ bufferPtr += sizeof(label); ++ break; ++ } ++ /* butc dump interface */ ++ case AUD_TDI: ++ { ++ struct tc_dumpInterface *di; ++ ++ di = (struct tc_dumpInterface *) ++ va_arg(vaList, struct tc_dumpInterface *); ++ if (di) ++ memcpy(bufferPtr, di, sizeof(*di)); ++ else ++ memset(bufferPtr, 0, sizeof(*di)); ++ bufferPtr += sizeof(*di); ++ break; ++ } ++ /* ++ * butc dump array ++ * An array of dump descriptions, but the AIX audit package assumes fixed ++ * length, so we can only do the first one for now. ++ */ ++ case AUD_TDA: ++ { ++ struct tc_dumpArray *da; ++ ++ da = (struct tc_dumpArray *) ++ va_arg(vaList, struct tc_dumpArray *); ++ if (da && da->tc_dumpArray_len) { ++ memcpy(bufferPtr, &da->tc_dumpArray_len, sizeof(u_int)); ++ bufferPtr += sizeof(u_int); ++ memcpy(bufferPtr, da->tc_dumpArray_val, ++ sizeof(da->tc_dumpArray_val[0])); ++ } else { ++ memset(bufferPtr, 0, sizeof(u_int)); ++ bufferPtr += sizeof(u_int); ++ memset(bufferPtr, 0, sizeof(da->tc_dumpArray_val[0])); ++ } ++ bufferPtr += sizeof(da->tc_dumpArray_val[0]); ++ break; ++ } ++ /* ++ * butc restore array ++ * An array of restore descriptions, but the AIX audit package assumes ++ * fixed length, so we can only do the first one for now. ++ */ ++ case AUD_TRA: ++ { ++ struct tc_restoreArray *ra; ++ ++ ra = (struct tc_restoreArray *) ++ va_arg(vaList, struct tc_restoreArray *); ++ if (ra && ra->tc_restoreArray_len) { ++ memcpy(bufferPtr, &ra->tc_restoreArray_len, sizeof(u_int)); ++ bufferPtr += sizeof(u_int); ++ memcpy(bufferPtr, ra->tc_restoreArray_val, ++ sizeof(ra->tc_restoreArray_val[0])); ++ } else { ++ memset(bufferPtr, 0, sizeof(u_int)); ++ bufferPtr += sizeof(u_int); ++ memset(bufferPtr, 0, sizeof(ra->tc_restoreArray_val[0])); ++ } ++ bufferPtr += sizeof(ra->tc_restoreArray_val[0]); ++ break; ++ } ++ /* butc tape controller status */ ++ { ++ struct tciStatusS *status; ++ ++ status = (struct tciStatusS *)va_arg(vaList, ++ struct tciStatusS *); ++ if (status) ++ memcpy(bufferPtr, status, sizeof(*status)); ++ else ++ memset(bufferPtr, 0, sizeof(*status)); ++ bufferPtr += sizeof(*status); ++ break; ++ } + default: + #ifdef AFS_AIX32_ENV + code = +@@ -177,6 +267,11 @@ printbuf(int rec, char *audEvent, char *afsName, afs_int32 hostId, + char *vaStr; + struct AFSFid *vaFid; + struct AFSCBFids *vaFids; ++ struct tc_tapeLabel *vaLabel; ++ struct tc_dumpInterface *vaDI; ++ struct tc_dumpArray *vaDA; ++ struct tc_restoreArray *vaRA; ++ struct tciStatusS *vaTCstatus; + int num = LogThreadNum(); + struct in_addr hostAddr; + time_t currenttime; +@@ -274,6 +369,102 @@ printbuf(int rec, char *audEvent, char *afsName, afs_int32 hostId, + + } + break; ++ case AUD_TLBL: /* butc tape label */ ++ vaLabel = va_arg(vaList, struct tc_tapeLabel *); ++ ++ if (vaLabel) { ++ audit_ops->append_msg("TAPELABEL %d:%.*s:%.*s:%u ", ++ vaLabel->size, ++ TC_MAXTAPELEN, vaLabel->afsname, ++ TC_MAXTAPELEN, vaLabel->pname, ++ vaLabel->tapeId); ++ } else { ++ audit_ops->append_msg("TAPELABEL "); ++ } ++ break; ++ case AUD_TDI: ++ vaDI = va_arg(vaList, struct tc_dumpInterface *); ++ ++ if (vaDI) { ++ audit_ops->append_msg( ++ "TCDUMPINTERFACE %.*s:%.*s:%.*s:%d:%d:%d:%d:%.*s:%.*s:%d:%d:%d:%d:%d ", ++ TC_MAXDUMPPATH, vaDI->dumpPath, TC_MAXNAMELEN, vaDI->volumeSetName, ++ TC_MAXNAMELEN, vaDI->dumpName, vaDI->parentDumpId, vaDI->dumpLevel, ++ vaDI->doAppend, ++ vaDI->tapeSet.id, TC_MAXHOSTLEN, vaDI->tapeSet.tapeServer, ++ TC_MAXFORMATLEN, vaDI->tapeSet.format, vaDI->tapeSet.maxTapes, ++ vaDI->tapeSet.a, vaDI->tapeSet.b, vaDI->tapeSet.expDate, ++ vaDI->tapeSet.expType); ++ } else { ++ audit_ops->append_msg("TCDUMPINTERFACE "); ++ } ++ break; ++ case AUD_TDA: ++ vaDA = va_arg(vaList, struct tc_dumpArray *); ++ ++ if (vaDA) { ++ u_int i; ++ struct tc_dumpDesc *desc; ++ struct in_addr hostAddr; ++ ++ desc = vaDA->tc_dumpArray_val; ++ if (desc) { ++ audit_ops->append_msg("DUMPS %d ", vaDA->tc_dumpArray_len); ++ for (i = 0; i < vaDA->tc_dumpArray_len; i++, desc++) { ++ hostAddr.s_addr = desc->hostAddr; ++ audit_ops->append_msg("DUMP %d:%d:%.*s:%d:%d:%d:%s ", ++ desc->vid, desc->vtype, TC_MAXNAMELEN, desc->name, ++ desc->partition, desc->date, desc->cloneDate, ++ inet_ntoa(hostAddr)); ++ } ++ } else { ++ audit_ops->append_msg("DUMPS 0 DUMP 0:0::0:0:0:0.0.0.0"); ++ } ++ } ++ break; ++ case AUD_TRA: ++ vaRA = va_arg(vaList, struct tc_restoreArray *); ++ ++ if (vaRA) { ++ u_int i; ++ struct tc_restoreDesc *desc; ++ struct in_addr hostAddr; ++ ++ desc = vaRA->tc_restoreArray_val; ++ if (desc) { ++ audit_ops->append_msg("RESTORES %d ", ++ vaRA->tc_restoreArray_len); ++ for(i = 0; i < vaRA->tc_restoreArray_len; i++, desc++) { ++ hostAddr.s_addr = desc->hostAddr; ++ audit_ops->append_msg( ++ "RESTORE %d:%.*s:%d:%d:%d:%d:%d:%d:%d:%s:%.*s:%.*s ", ++ desc->flags, TC_MAXTAPELEN, desc->tapeName, ++ desc->dbDumpId, desc->initialDumpId, ++ desc->position, desc->origVid, desc->vid, ++ desc->partition, desc->dumpLevel, ++ inet_ntoa(hostAddr), TC_MAXNAMELEN, ++ desc->oldName, TC_MAXNAMELEN, desc->newName); ++ } ++ } else { ++ audit_ops->append_msg( ++ "RESTORES 0 RESTORE 0::0:0:0:0:0:0:0:0.0.0.0::: "); ++ } ++ } ++ break; ++ case AUD_TSTT: ++ vaTCstatus = va_arg(vaList, struct tciStatusS *); ++ ++ if (vaTCstatus) ++ audit_ops->append_msg("TCSTATUS %.*s:%d:%d:%d:%d:%.*s:%d:%d ", ++ TC_MAXNAMELEN, vaTCstatus->taskName, ++ vaTCstatus->taskId, vaTCstatus->flags, ++ vaTCstatus->dbDumpId, vaTCstatus->nKBytes, ++ TC_MAXNAMELEN, vaTCstatus->volumeName, ++ vaTCstatus->volsFailed, ++ vaTCstatus->lastPolled); ++ else ++ audit_ops->append_msg("TCSTATUS "); ++ break; + default: + audit_ops->append_msg("--badval-- "); + break; +diff --git a/src/audit/audit.h b/src/audit/audit.h +index 0014f86..93413ca 100644 +--- a/src/audit/audit.h ++++ b/src/audit/audit.h +@@ -23,6 +23,12 @@ + #define AUD_RESID 20 /* resid in variable list */ + #define AUD_RSSIZERANGE 21 /* rssizerange in variable list */ + #define AUD_LOOKUPINFO 22 /* LookupInfo in variable list */ ++/* next 5 lines for butc */ ++#define AUD_TLBL 30 /* Tape Controller label */ ++#define AUD_TDI 31 /* Tape Controller dump interface */ ++#define AUD_TDA 32 /* Tape Controller dump array */ ++#define AUD_TRA 33 /* Tape Controller restore array */ ++#define AUD_TSTT 34 /* Tape Controller status struct */ + + /* + * Note: the master definitions of these error codes come from *.et +@@ -287,6 +293,21 @@ + #define SREMIORemoteGetHSMdata "AFS_RE_HSMdata" + #define SREMIOPrefetch "AFS_RE_Prefetch" + ++#define TC_StartEvent "AFS_TC_Start" ++#define TC_LabelTapeEvent "AFS_TC_LabelTape" ++#define TC_PerformDumpEvent "AFS_TC_PerformDump" ++#define TC_PerformRestoreEvent "AFS_TC_PerformRestore" ++#define TC_ReadLabelEvent "AFS_TC_ReadLabel" ++#define TC_RestoreDbEvent "AFS_TC_RestoreDb" ++#define TC_SaveDbEvent "AFS_TC_SaveDb" ++#define TC_ScanDumpsEvent "AFS_TC_ScanDumps" ++#define TC_TCInfoEvent "AFS_TC_TCInfo" ++#define TC_DeleteDumpEvent "AFS_TC_DeleteDump" ++#define TC_GetStatusEvent "AFS_TC_GetStatus" ++#define TC_EndStatusEvent "AFS_TC_EndStatus" ++#define TC_RequestAbortEvent "AFS_TC_RequestAbort" ++#define TC_ScanStatusEvent "AFS_TC_ScanStatus" ++ + + /* prototypes for audit functions */ + int osi_audit(char *audEvent, afs_int32 errCode, ...); +diff --git a/src/bucoord/bucoord_internal.h b/src/bucoord/bucoord_internal.h +index 83622b4..d372ac2 100644 +--- a/src/bucoord/bucoord_internal.h ++++ b/src/bucoord/bucoord_internal.h +@@ -119,6 +119,8 @@ struct cmd_parmdesc; + extern afs_int32 bc_ParseExpiration(struct cmd_parmdesc *paramPtr, + afs_int32 *expType, afs_int32 *expDate); + /* main.c */ ++extern int localauth, nobutcauth; ++extern char tcell[]; + extern time_t tokenExpires; + extern afs_int32 doDispatch(afs_int32, char *[], afs_int32); + extern void bc_HandleMisc(afs_int32 code); +diff --git a/src/bucoord/dump.c b/src/bucoord/dump.c +index cf0f474..54f0851 100644 +--- a/src/bucoord/dump.c ++++ b/src/bucoord/dump.c +@@ -17,6 +17,7 @@ + + #include + #include ++#include + #ifdef HAVE_STDINT_H + # include + #endif +@@ -478,15 +479,40 @@ bc_GetConn(struct bc_config *aconfig, afs_int32 aport, + struct rx_connection **tconn) + { + afs_uint32 host; ++ afs_int32 code; + unsigned short port; + static struct rx_securityClass *rxsc; ++ static afs_int32 scIndex; + struct bc_hostEntry *te; + + *tconn = (struct rx_connection *)0; + + /* use non-secure connections to butc */ +- if (!rxsc) +- rxsc = rxnull_NewClientSecurityObject(); ++ if (!rxsc) { ++ struct afsconf_dir *dir; ++ afsconf_secflags flags = AFSCONF_SECOPTS_FALLBACK_NULL; ++ char *cname; ++ ++ if (nobutcauth) ++ flags |= AFSCONF_SECOPTS_NOAUTH; ++ if (localauth) { ++ flags |= AFSCONF_SECOPTS_LOCALAUTH; ++ dir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH); ++ } else { ++ dir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH); ++ } ++ if (tcell[0] == '\0') ++ cname = NULL; ++ else ++ cname = tcell; ++ /* No need for cell info since butc is not a registered service */ ++ code = afsconf_PickClientSecObj(dir, flags, NULL, cname, &rxsc, &scIndex, ++ NULL); ++ if (dir) ++ afsconf_Close(dir); ++ if (code) ++ return -1; ++ } + if (!rxsc || !aconfig) + return (-1); + +@@ -499,8 +525,8 @@ bc_GetConn(struct bc_config *aconfig, afs_int32 aport, + + port = htons(BC_TAPEPORT + aport); + +- /* servers is 1; sec index is 0 */ +- *tconn = rx_NewConnection(host, port, 1, rxsc, 0); ++ /* servers is 1 */ ++ *tconn = rx_NewConnection(host, port, 1, rxsc, scIndex); + return ((*tconn ? 0 : -1)); + } + } +diff --git a/src/bucoord/main.c b/src/bucoord/main.c +index 3f38d07..1625069 100644 +--- a/src/bucoord/main.c ++++ b/src/bucoord/main.c +@@ -54,7 +54,7 @@ + #include "bucoord_internal.h" + #include "bucoord_prototypes.h" + +-int localauth, interact; ++int localauth, interact, nobutcauth; + char tcell[64]; + + /* +@@ -305,6 +305,7 @@ MyBeforeProc(struct cmd_syndesc *as, void *arock) + /* Handling the command line opcode */ + if (!bcInit) { + localauth = ((as && as->parms[14].items) ? 1 : 0); ++ nobutcauth = ((as && as->parms[16].items) ? 1 : 0); + if (as && as->parms[15].items) + strcpy(tcell, as->parms[15].items->data); + else +@@ -445,6 +446,8 @@ add_std_args(struct cmd_syndesc *ts) + cmd_AddParm(ts, "-localauth", CMD_FLAG, CMD_OPTIONAL, + "local authentication"); + cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name"); ++ cmd_AddParm(ts, "-nobutcauth", CMD_FLAG, CMD_OPTIONAL, ++ "no authentication to butc"); + } + + int +diff --git a/src/butc/Makefile.in b/src/butc/Makefile.in +index 078fd6e..0a97ba5 100644 +--- a/src/butc/Makefile.in ++++ b/src/butc/Makefile.in +@@ -41,6 +41,7 @@ LIBS=${TOP_LIBDIR}/libbudb.a \ + ${TOP_LIBDIR}/libdes.a \ + ${TOP_LIBDIR}/librx.a \ + ${TOP_LIBDIR}/libsys.a \ ++ ${TOP_LIBDIR}/libaudit.a \ + ${TOP_LIBDIR}/liblwp.a \ + ${TOP_LIBDIR}/libcmd.a \ + ${TOP_LIBDIR}/libafscom_err.a \ +diff --git a/src/butc/butc_prototypes.h b/src/butc/butc_prototypes.h +index 1c62c34..85a3799 100644 +--- a/src/butc/butc_prototypes.h ++++ b/src/butc/butc_prototypes.h +@@ -32,5 +32,10 @@ extern void *saveDbToTape(void *); + extern void *restoreDbFromTape(void *); + extern void *KeepAlive(void *); + ++/* tcmain.c */ ++ ++extern struct afsconf_dir *butc_confdir; ++extern int allow_unauth; ++ + #endif + +diff --git a/src/butc/tcmain.c b/src/butc/tcmain.c +index 2c4154d..79e1bbf 100644 +--- a/src/butc/tcmain.c ++++ b/src/butc/tcmain.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -106,18 +107,12 @@ afs_int32 BufferSize; /* Size in B stored for data */ + char *centralLogFile; + afs_int32 lastLog; /* Log last pass info */ + int rxBind = 0; ++struct afsconf_dir *butc_confdir; ++int allow_unauth = 0; + + #define ADDRSPERSITE 16 /* Same global is in rx/rx_user.c */ + afs_uint32 SHostAddrs[ADDRSPERSITE]; + +-/* dummy routine for the audit work. It should do nothing since audits */ +-/* occur at the server level and bos is not a server. */ +-int +-osi_audit(void) +-{ +- return 0; +-} +- + static afs_int32 + SafeATOL(char *anum) + { +@@ -843,8 +838,8 @@ xbsa_shutdown(int x) + static int + WorkerBee(struct cmd_syndesc *as, void *arock) + { +- afs_int32 code; +- struct rx_securityClass *(securityObjects[1]); ++ afs_int32 code, numClasses; ++ struct rx_securityClass *(nullObjects[1]), **secObjs, **allObjs; + struct rx_service *service; + time_t tokenExpires; + char cellName[64]; +@@ -859,6 +854,8 @@ WorkerBee(struct cmd_syndesc *as, void *arock) + PROCESS dbWatcherPid; + #endif + afs_uint32 host = htonl(INADDR_ANY); ++ char *auditFileName = NULL; ++ char *auditInterface = NULL; + + debugLevel = 0; + +@@ -1004,6 +1001,29 @@ WorkerBee(struct cmd_syndesc *as, void *arock) + } + } + ++ /* Open the configuration directory */ ++ butc_confdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH); ++ if (butc_confdir == NULL) { ++ TLog(0, "Failed to open server configuration directory"); ++ exit(1); ++ } ++ ++ /* Start auditing */ ++ osi_audit_init(); ++ if (as->parms[9].items) { ++ auditFileName = as->parms[9].items->data; ++ } ++ if (auditFileName != NULL) ++ osi_audit_file(auditFileName); ++ if (as->parms[10].items) { ++ auditInterface = as->parms[10].items->data; ++ if (osi_audit_interface(auditInterface)) { ++ TLog(0, "Invalid audit interface '%s'\n", auditInterface); ++ exit(1); ++ } ++ } ++ osi_audit(TC_StartEvent, 0, AUD_END); ++ + if (as->parms[1].items) { + debugLevel = SafeATOL(as->parms[1].items->data); + if (debugLevel == -1) { +@@ -1044,6 +1064,13 @@ WorkerBee(struct cmd_syndesc *as, void *arock) + + localauth = (as->parms[5].items ? 1 : 0); + rxBind = (as->parms[8].items ? 1 : 0); ++ allow_unauth = (as->parms[11].items ? 1 : 0); ++ ++ if (!allow_unauth && !localauth) { ++ const char *errstr = "Neither -localauth nor -allow_unauthenticated was provided; refusing to start in unintended insecure configuration\n"; ++ TLog(0, "%s", (char *)errstr); ++ exit(1); ++ } + + if (rxBind) { + afs_int32 ccode; +@@ -1089,19 +1116,48 @@ WorkerBee(struct cmd_syndesc *as, void *arock) + + /* initialize database support, volume support, and logs */ + +- /* Create a single security object, in this case the null security +- * object, for unauthenticated connections, which will be used to control +- * security on connections made to this server ++ /* ++ * Create security objects for the Rx server functionality. Historically ++ * this was a single rxnull security object, since the tape controller was ++ * run by an operator that had local access to the tape device and some ++ * administrative privilege in the cell (to be able to perform volume-level ++ * accesses), but on a machine that was not necessarily trusted to hold the ++ * cell-wide key. ++ * ++ * Such a configuration is, of course, insecure because anyone can make ++ * inbound RPCs and manipulate the database, including creating bogus ++ * dumps and restoring them! Additionally, in modern usage, butc is ++ * frequently run with -localauth to authenticate its outbound connections ++ * to the volservers and budb with the cell-wide key, in which case the ++ * cell-wide key is present and could be used to authenticate incoming ++ * connections as well. ++ * ++ * If -localauth is in use, create the full barrage of server security ++ * objects, including rxkad, so that inbound connections can be verified ++ * to only be made by authenticated clients. Otherwise, only the rxnull ++ * class is in use with a single server security object. Note that butc ++ * will refuse to start in this configuration unless the ++ * "-allow_unauthenticated" flag is provided, indicating that the operator ++ * has ensured that incoming connections are appropriately restricted by ++ * firewall configuration or network topology. + */ + +- securityObjects[0] = rxnull_NewServerSecurityObject(); +- if (!securityObjects[0]) { +- TLog(0, "rxnull_NewServerSecurityObject"); +- exit(1); ++ if (allow_unauth) { ++ nullObjects[RX_SECIDX_NULL] = rxnull_NewServerSecurityObject(); ++ if (!nullObjects[RX_SECIDX_NULL]) { ++ TLog(0, "rxnull_NewServerSecurityObject"); ++ exit(1); ++ } ++ numClasses = 1; ++ secObjs = nullObjects; ++ } else { ++ /* Must be -localauth, so the cell keys are available. */ ++ afsconf_BuildServerSecurityObjects(butc_confdir, 0, &allObjs, &numClasses); ++ secObjs = allObjs; + } + + service = +- rx_NewServiceHost(host, 0, 1, "BUTC", securityObjects, 1, TC_ExecuteRequest); ++ rx_NewServiceHost(host, 0, 1, "BUTC", secObjs, numClasses, TC_ExecuteRequest); + if (!service) { + TLog(0, "rx_NewService"); + exit(1); +@@ -1204,6 +1260,11 @@ main(int argc, char **argv) + "Force multiple XBSA server support"); + cmd_AddParm(ts, "-rxbind", CMD_FLAG, CMD_OPTIONAL, + "bind Rx socket"); ++ cmd_AddParm(ts, "-auditlog", CMD_SINGLE, CMD_OPTIONAL, "location of audit log"); ++ cmd_AddParm(ts, "-audit-interface", CMD_SINGLE, CMD_OPTIONAL, ++ "interface to use for audit logging"); ++ cmd_AddParm(ts, "-allow_unauthenticated", CMD_FLAG, CMD_OPTIONAL, ++ "allow unauthenticated inbound RPCs (requires firewalling)"); + + /* Initialize dirpaths */ + if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) { +diff --git a/src/butc/tcprocs.c b/src/butc/tcprocs.c +index 9efcbe8..e22a5ca 100644 +--- a/src/butc/tcprocs.c ++++ b/src/butc/tcprocs.c +@@ -46,18 +46,41 @@ + #include "butc_xbsa.h" + #include "butc_prototypes.h" + #include "butc_internal.h" ++#include "afs/audit.h" + + static int CopyDumpDesc(struct tc_dumpDesc *, tc_dumpArray *); + static int CopyRestoreDesc(struct tc_restoreDesc *, tc_restoreArray *); + static int CopyTapeSetDesc(struct tc_tapeSet *, struct tc_tapeSet *); + ++/* Helpers implementing RPC backends */ ++static afs_int32 SLabelTape(struct rx_call *acid, struct tc_tapeLabel *label, ++ afs_uint32 *taskId); ++static afs_int32 SPerformDump(struct rx_call *rxCallId, ++ struct tc_dumpInterface *tcdiPtr, ++ tc_dumpArray *tc_dumpArrayPtr, afs_int32 *taskId); ++static afs_int32 SPerformRestore(struct rx_call *acid, char *dumpSetName, ++ tc_restoreArray *arestores, afs_int32 *taskId); ++static afs_int32 SReadLabel(struct rx_call *acid, struct tc_tapeLabel *label, ++ afs_uint32 *taskId); ++static afs_int32 SRestoreDb(struct rx_call *rxCall, afs_uint32 *taskId); ++static afs_int32 SSaveDb(struct rx_call *rxCall, Date archiveTime, ++ afs_uint32 *taskId); ++static afs_int32 SScanDumps(struct rx_call *acid, afs_int32 addDbFlag, ++ afs_uint32 *taskId); ++static afs_int32 STCInfo(struct rx_call *acid, struct tc_tcInfo *tciptr); ++static afs_int32 SDeleteDump(struct rx_call *acid, afs_uint32 dumpID, ++ afs_uint32 *taskId); ++ + int + callPermitted(struct rx_call *call) + { +- /* before this code can be used, the rx connection, on the bucoord side, must */ +- /* be changed so that it will set up for token passing instead of using a */ +- /* simple rx connection that, below, returns a value of 0 from rx_SecurityClassOf */ +- return 1; ++ /* ++ * If in backwards compat mode, allow anyone; otherwise, only ++ * superusers are allowed. ++ */ ++ if (allow_unauth) ++ return 1; ++ return afsconf_SuperUser(butc_confdir, call, NULL); + } + + /* ----------------------------- +@@ -139,6 +162,17 @@ CopyTapeSetDesc(struct tc_tapeSet *toPtr, struct tc_tapeSet *fromPtr) + + afs_int32 + STC_LabelTape(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *taskId) ++{ ++ afs_int32 code; ++ ++ code = SLabelTape(acid, label, taskId); ++ osi_auditU(acid, TC_LabelTapeEvent, code, ++ AUD_TLBL, label, AUD_INT, *taskId, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++SLabelTape(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *taskId) + { + #ifdef AFS_PTHREAD_ENV + pthread_t pid; +@@ -214,7 +248,20 @@ STC_LabelTape(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *task + */ + + afs_int32 +-STC_PerformDump(struct rx_call *rxCallId, struct tc_dumpInterface *tcdiPtr, tc_dumpArray *tc_dumpArrayPtr, afs_int32 *taskId) ++STC_PerformDump(struct rx_call *call, struct tc_dumpInterface *di, ++ tc_dumpArray *da, afs_int32 *taskId) ++{ ++ afs_int32 code; ++ ++ code = SPerformDump(call, di, da, taskId); ++ osi_auditU(call, TC_PerformDumpEvent, code, ++ AUD_TDI, di, AUD_TDA, da, AUD_INT, *taskId, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++SPerformDump(struct rx_call *rxCallId, struct tc_dumpInterface *tcdiPtr, ++ tc_dumpArray *tc_dumpArrayPtr, afs_int32 *taskId) + { + struct dumpNode *newNode = 0; + statusP statusPtr = 0; +@@ -310,7 +357,20 @@ STC_PerformDump(struct rx_call *rxCallId, struct tc_dumpInterface *tcdiPtr, tc_d + } + + afs_int32 +-STC_PerformRestore(struct rx_call *acid, char *dumpSetName, tc_restoreArray *arestores, afs_int32 *taskID) ++STC_PerformRestore(struct rx_call *call, char *dumpSetName, ++ tc_restoreArray *ra, afs_int32 *taskId) ++{ ++ afs_int32 code; ++ ++ code = SPerformRestore(call, dumpSetName, ra, taskId); ++ osi_auditU(call, TC_PerformRestoreEvent, code, ++ AUD_STR, dumpSetName, AUD_TRA, ra, AUD_INT, *taskId, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++SPerformRestore(struct rx_call *acid, char *dumpSetName, ++ tc_restoreArray *arestores, afs_int32 *taskID) + { + struct dumpNode *newNode; + statusP statusPtr; +@@ -384,7 +444,18 @@ STC_PerformRestore(struct rx_call *acid, char *dumpSetName, tc_restoreArray *are + } + + afs_int32 +-STC_ReadLabel(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *taskId) ++STC_ReadLabel(struct rx_call *call, struct tc_tapeLabel *label, afs_uint32 *taskId) ++{ ++ afs_int32 code; ++ ++ code = SReadLabel(call, label, taskId); ++ osi_auditU(call, TC_ReadLabelEvent, code, ++ AUD_TLBL, label, AUD_INT, *taskId, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++SReadLabel(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *taskId) + { + afs_int32 code; + +@@ -405,7 +476,17 @@ STC_ReadLabel(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *task + */ + + afs_int32 +-STC_RestoreDb(struct rx_call *rxCall, afs_uint32 *taskId) ++STC_RestoreDb(struct rx_call *call, afs_uint32 *taskId) ++{ ++ afs_int32 code; ++ ++ code = SRestoreDb(call, taskId); ++ osi_auditU(call, TC_RestoreDbEvent, code, AUD_INT, *taskId, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++SRestoreDb(struct rx_call *rxCall, afs_uint32 *taskId) + { + #ifdef AFS_PTHREAD_ENV + pthread_t pid; +@@ -471,7 +552,18 @@ STC_RestoreDb(struct rx_call *rxCall, afs_uint32 *taskId) + */ + + afs_int32 +-STC_SaveDb(struct rx_call *rxCall, Date archiveTime, afs_uint32 *taskId) ++STC_SaveDb(struct rx_call *call, Date archiveTime, afs_uint32 *taskId) ++{ ++ afs_int32 code; ++ ++ code = SSaveDb(call, archiveTime, taskId); ++ osi_auditU(call, TC_SaveDbEvent, code, ++ AUD_DATE, archiveTime, AUD_INT, *taskId, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++SSaveDb(struct rx_call *rxCall, Date archiveTime, afs_uint32 *taskId) + { + #ifdef AFS_PTHREAD_ENV + pthread_t pid; +@@ -550,7 +642,18 @@ STC_SaveDb(struct rx_call *rxCall, Date archiveTime, afs_uint32 *taskId) + */ + + afs_int32 +-STC_ScanDumps(struct rx_call *acid, afs_int32 addDbFlag, afs_uint32 *taskId) ++STC_ScanDumps(struct rx_call *call, afs_int32 addDbFlag, afs_uint32 *taskId) ++{ ++ afs_int32 code; ++ ++ code = SScanDumps(call, addDbFlag, taskId); ++ osi_auditU(call, TC_ScanDumpsEvent, code, ++ AUD_INT, addDbFlag, AUD_INT, *taskId, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++SScanDumps(struct rx_call *acid, afs_int32 addDbFlag, afs_uint32 *taskId) + { + #ifdef AFS_PTHREAD_ENV + pthread_t pid; +@@ -625,7 +728,17 @@ STC_ScanDumps(struct rx_call *acid, afs_int32 addDbFlag, afs_uint32 *taskId) + */ + + afs_int32 +-STC_TCInfo(struct rx_call *acid, struct tc_tcInfo *tciptr) ++STC_TCInfo(struct rx_call *call, struct tc_tcInfo *ti) ++{ ++ afs_int32 code; ++ ++ code = STCInfo(call, ti); ++ osi_auditU(call, TC_TCInfoEvent, code, AUD_INT, ti->tcVersion, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++STCInfo(struct rx_call *acid, struct tc_tcInfo *tciptr) + { + if (callPermitted(acid) == 0) + return (TC_NOTPERMITTED); +@@ -637,7 +750,18 @@ STC_TCInfo(struct rx_call *acid, struct tc_tcInfo *tciptr) + /* STC_DeleteDump + */ + afs_int32 +-STC_DeleteDump(struct rx_call *acid, afs_uint32 dumpID, afs_uint32 *taskId) ++STC_DeleteDump(struct rx_call *call, afs_uint32 dumpID, afs_uint32 *taskId) ++{ ++ afs_int32 code; ++ ++ code = SDeleteDump(call, dumpID, taskId); ++ osi_auditU(call, TC_DeleteDumpEvent, code, ++ AUD_DATE, dumpID, AUD_INT, *taskId, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++SDeleteDump(struct rx_call *acid, afs_uint32 dumpID, afs_uint32 *taskId) + { + afs_int32 code = TC_BADTASK; /* If not compiled -Dxbsa then fail */ + #ifdef xbsa +diff --git a/src/butc/tcstatus.c b/src/butc/tcstatus.c +index 1bd280f..883f46d 100644 +--- a/src/butc/tcstatus.c ++++ b/src/butc/tcstatus.c +@@ -34,6 +34,8 @@ + + #include "error_macros.h" + #include "butc_xbsa.h" ++#include "afs/audit.h" ++ + /* tape coordinator - task status management */ + extern afs_int32 xbsaType; + +@@ -41,6 +43,13 @@ dlqlinkT statusHead; + struct Lock statusQueueLock; + struct Lock cmdLineLock; + ++static afs_int32 SGetStatus(struct rx_call *call, afs_uint32 taskId, ++ struct tciStatusS *statusPtr); ++static afs_int32 SEndStatus(struct rx_call *call, afs_uint32 taskId); ++static afs_int32 SRequestAbort(struct rx_call *call, afs_uint32 taskId); ++static afs_int32 SScanStatus(struct rx_call *call, afs_uint32 *taskId, ++ struct tciStatusS *statusPtr, afs_uint32 *flags); ++ + /* STC_GetStatus + * get the status of a task + * entry: +@@ -51,7 +60,19 @@ struct Lock cmdLineLock; + + afs_int32 + STC_GetStatus(struct rx_call *call, afs_uint32 taskId, +- struct tciStatusS *statusPtr) ++ struct tciStatusS *status) ++{ ++ afs_int32 code; ++ ++ code = SGetStatus(call, taskId, status); ++ osi_auditU(call, TC_GetStatusEvent, code, ++ AUD_INT, taskId, AUD_TSTT, status, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++SGetStatus(struct rx_call *call, afs_uint32 taskId, ++ struct tciStatusS *statusPtr) + { + statusP ptr; + int retval = 0; +@@ -82,6 +103,16 @@ STC_GetStatus(struct rx_call *call, afs_uint32 taskId, + + afs_int32 + STC_EndStatus(struct rx_call *call, afs_uint32 taskId) ++{ ++ afs_int32 code; ++ ++ code = SEndStatus(call, taskId); ++ osi_auditU(call, TC_EndStatusEvent, code, AUD_INT, taskId, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++SEndStatus(struct rx_call *call, afs_uint32 taskId) + { + statusP ptr; + int retval = 0; +@@ -103,6 +134,16 @@ STC_EndStatus(struct rx_call *call, afs_uint32 taskId) + + afs_int32 + STC_RequestAbort(struct rx_call *call, afs_uint32 taskId) ++{ ++ afs_int32 code; ++ ++ code = SRequestAbort(call, taskId); ++ osi_auditU(call, TC_RequestAbortEvent, code, AUD_INT, taskId, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++SRequestAbort(struct rx_call *call, afs_uint32 taskId) + { + statusP ptr; + int retval = 0; +@@ -138,7 +179,19 @@ STC_RequestAbort(struct rx_call *call, afs_uint32 taskId) + + afs_int32 + STC_ScanStatus(struct rx_call *call, afs_uint32 *taskId, +- struct tciStatusS *statusPtr, afs_uint32 *flags) ++ struct tciStatusS *status, afs_uint32 *flags) ++{ ++ afs_int32 code; ++ ++ code = SScanStatus(call, taskId, status, flags); ++ osi_auditU(call, TC_ScanStatusEvent, code, ++ AUD_INT, *taskId, AUD_TSTT, status, AUD_INT, *flags, AUD_END); ++ return code; ++} ++ ++static afs_int32 ++SScanStatus(struct rx_call *call, afs_uint32 *taskId, ++ struct tciStatusS *statusPtr, afs_uint32 *flags) + { + statusP ptr = 0; + dlqlinkP dlqPtr; diff --git a/debian/patches/CVE-2018-16948.patch b/debian/patches/CVE-2018-16948.patch new file mode 100644 index 000000000..69c9d7c85 --- /dev/null +++ b/debian/patches/CVE-2018-16948.patch @@ -0,0 +1,172 @@ +From: Markus Koschany +Date: Fri, 21 Sep 2018 15:58:50 +0200 +Subject: CVE-2018-16948 + +Bug-Debian: https://bugs.debian.org/908616 +Origin: https://www.openafs.org/pages/security/openafs-sa-2018-002-stable16.patch +--- + src/afs/afs_callback.c | 2 ++ + src/budb/procs.c | 1 + + src/butc/tcprocs.c | 3 +++ + src/butc/tcstatus.c | 4 ++-- + src/kauth/kaprocs.c | 1 + + src/ptserver/ptprocs.c | 4 ++-- + src/ubik/vote.c | 1 + + src/volser/volprocs.c | 3 +++ + 8 files changed, 15 insertions(+), 4 deletions(-) + +diff --git a/src/afs/afs_callback.c b/src/afs/afs_callback.c +index 51b6b61..6a95ed4 100644 +--- a/src/afs/afs_callback.c ++++ b/src/afs/afs_callback.c +@@ -309,6 +309,7 @@ SRXAFSCB_GetLock(struct rx_call *a_call, afs_int32 a_index, + XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_GETLOCK); + + AFS_STATCNT(SRXAFSCB_GetLock); ++ memset(a_result, 0, sizeof(*a_result)); + nentries = sizeof(ltable) / sizeof(struct ltable); + if (a_index < 0 || a_index >= nentries+afs_cellindex) { + /* +@@ -1632,6 +1633,7 @@ SRXAFSCB_TellMeAboutYourself(struct rx_call *a_call, + ObtainReadLock(&afs_xinterface); + + /* return all network interface addresses */ ++ memset(addr, 0, sizeof(*addr)); + addr->numberOfInterfaces = afs_cb_interface.numberOfInterfaces; + addr->uuid = afs_cb_interface.uuid; + for (i = 0; i < afs_cb_interface.numberOfInterfaces; i++) { +diff --git a/src/budb/procs.c b/src/budb/procs.c +index 51f3102..de55834 100644 +--- a/src/budb/procs.c ++++ b/src/budb/procs.c +@@ -437,6 +437,7 @@ FillDumpEntry(struct ubik_trans *ut, dbadr da, void *rock) + struct budb_dumpEntry *dump = (struct budb_dumpEntry *)rock; + struct dump d, ad; + ++ memset(dump, 0, sizeof(*dump)); + if (dbread(ut, da, &d, sizeof(d))) + return BUDB_IO; + dump->id = ntohl(d.id); +diff --git a/src/butc/tcprocs.c b/src/butc/tcprocs.c +index e22a5ca..25b6d5b 100644 +--- a/src/butc/tcprocs.c ++++ b/src/butc/tcprocs.c +@@ -459,6 +459,9 @@ SReadLabel(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *taskId) + { + afs_int32 code; + ++ memset(label, 0, sizeof(*label)); ++ /* Synchronous, so no "real" ID; don't send stack garbage on the wire */ ++ *taskId = 0; + #ifdef xbsa + if (CONF_XBSA) + return (TC_BADTASK); /* ReadLabel does not apply if XBSA */ +diff --git a/src/butc/tcstatus.c b/src/butc/tcstatus.c +index 883f46d..dcc4d19 100644 +--- a/src/butc/tcstatus.c ++++ b/src/butc/tcstatus.c +@@ -77,14 +77,13 @@ SGetStatus(struct rx_call *call, afs_uint32 taskId, + statusP ptr; + int retval = 0; + ++ memset(statusPtr, 0, sizeof(*statusPtr)); + if (callPermitted(call) == 0) + return (TC_NOTPERMITTED); + + lock_Status(); + ptr = findStatus(taskId); + if (ptr) { +- /* strcpy(statusPtr->status, ptr->status); */ +- + strcpy(statusPtr->taskName, ptr->taskName); + strcpy(statusPtr->volumeName, ptr->volumeName); + statusPtr->taskId = ptr->taskId; +@@ -196,6 +195,7 @@ SScanStatus(struct rx_call *call, afs_uint32 *taskId, + statusP ptr = 0; + dlqlinkP dlqPtr; + ++ memset(statusPtr, 0, sizeof(*statusPtr)); + if (callPermitted(call) == 0) + return (TC_NOTPERMITTED); + +diff --git a/src/kauth/kaprocs.c b/src/kauth/kaprocs.c +index 7298b86..8584ad3 100644 +--- a/src/kauth/kaprocs.c ++++ b/src/kauth/kaprocs.c +@@ -1693,6 +1693,7 @@ kamListEntry(struct rx_call *call, + afs_int32 caller; + struct kaentry tentry; + ++ memset(name, 0, sizeof(*name)); + COUNT_REQ(ListEntry); + if ((code = InitAuthServ(&tt, LOCKREAD, this_op))) + return code; +diff --git a/src/ptserver/ptprocs.c b/src/ptserver/ptprocs.c +index f9f48fc..2303c73 100644 +--- a/src/ptserver/ptprocs.c ++++ b/src/ptserver/ptprocs.c +@@ -687,7 +687,7 @@ idToName(struct rx_call *call, idlist *aid, namelist *aname) + return 0; + if (size < 0 || size > INT_MAX / PR_MAXNAMELEN) + return PRTOOMANY; +- aname->namelist_val = (prname *) malloc(size * PR_MAXNAMELEN); ++ aname->namelist_val = (prname *) calloc(size, PR_MAXNAMELEN); + aname->namelist_len = 0; + if (aname->namelist_val == 0) + return PRNOMEM; +@@ -1647,6 +1647,7 @@ put_prentries(struct prentry *tentry, prentries *bulkentries) + entry = (struct prlistentries *)bulkentries->prentries_val; + entry += bulkentries->prentries_len; + ++ memset(entry, 0, sizeof(*entry)); + entry->flags = tentry->flags >> PRIVATE_SHIFT; + if (entry->flags == 0) { + entry->flags = +@@ -1661,7 +1662,6 @@ put_prentries(struct prentry *tentry, prentries *bulkentries) + entry->nusers = tentry->nusers; + entry->count = tentry->count; + strncpy(entry->name, tentry->name, PR_MAXNAMELEN); +- memset(entry->reserved, 0, sizeof(entry->reserved)); + bulkentries->prentries_len++; + return 0; + } +diff --git a/src/ubik/vote.c b/src/ubik/vote.c +index 13af885..f7bef1a 100644 +--- a/src/ubik/vote.c ++++ b/src/ubik/vote.c +@@ -406,6 +406,7 @@ SVOTE_Debug(struct rx_call * rxcall, struct ubik_debug * aparm) + /* fill in the basic debug structure. Note the the RPC protocol transfers, + * integers in host order. */ + ++ memset(aparm, 0, sizeof(*aparm)); + aparm->now = FT_ApproxTime(); + aparm->lastYesTime = ubik_lastYesTime; + aparm->lastYesHost = ntohl(lastYesHost); +diff --git a/src/volser/volprocs.c b/src/volser/volprocs.c +index 90346b8..10f2955 100644 +--- a/src/volser/volprocs.c ++++ b/src/volser/volprocs.c +@@ -432,6 +432,7 @@ SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition + struct diskPartition64 *dp = (struct diskPartition64 *) + malloc(sizeof(struct diskPartition64)); + ++ memset(partition, 0, sizeof(*partition)); + code = VolPartitionInfo(acid, pname, dp); + if (!code) { + strncpy(partition->name, dp->name, 32); +@@ -451,6 +452,7 @@ SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64 + { + afs_int32 code; + ++ memset(partition, 0, sizeof(*partition)); + code = VolPartitionInfo(acid, pname, partition); + osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END); + return code; +@@ -2848,6 +2850,7 @@ VolMonitor(struct rx_call *acid, transDebugEntries *transInfo) + goto done; /*no active transactions */ + for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */ + nt = tt->next; ++ memset(pntr, 0, sizeof(*pntr)); + VTRANS_OBJ_LOCK(tt); + pntr->tid = tt->tid; + pntr->time = tt->time; diff --git a/debian/patches/CVE-2018-16949.patch b/debian/patches/CVE-2018-16949.patch new file mode 100644 index 000000000..0edb86663 --- /dev/null +++ b/debian/patches/CVE-2018-16949.patch @@ -0,0 +1,142 @@ +From: Markus Koschany +Date: Fri, 21 Sep 2018 15:59:08 +0200 +Subject: CVE-2018-16949 + +Bug-Debian: https://bugs.debian.org/908616 +Origin: https://www.openafs.org/pages/security/openafs-sa-2018-003-stable16.patch +--- + src/budb/budb.rg | 2 +- + src/rxgen/rpc_parse.c | 5 ++++- + src/vlserver/vldbint.xg | 7 ++++++- + src/volser/volint.xg | 15 ++++++++------- + 4 files changed, 19 insertions(+), 10 deletions(-) + +diff --git a/src/budb/budb.rg b/src/budb/budb.rg +index 1ec45f1..6e61652 100644 +--- a/src/budb/budb.rg ++++ b/src/budb/budb.rg +@@ -224,7 +224,7 @@ typedef struct budb_volumeEntry budb_volumeList; + typedef struct budb_dumpEntry budb_dumpList; + typedef struct budb_tapeEntry budb_tapeList; + typedef afs_int32 budb_dumpsList; +-typedef char charListT<>; ++typedef char charListT<4096>; + + %#define BUDB_TEXT_COMPLETE 1 + +diff --git a/src/rxgen/rpc_parse.c b/src/rxgen/rpc_parse.c +index 8ce005d..f94ba65 100644 +--- a/src/rxgen/rpc_parse.c ++++ b/src/rxgen/rpc_parse.c +@@ -458,6 +458,9 @@ get_declaration(declaration * dec, defkind dkind) + } + dec->rel = REL_ARRAY; + if (peekscan(TOK_RANGLE, &tok)) { ++ if ((dkind == DEF_INPARAM) || (dkind == DEF_INOUTPARAM)) { ++ error("input arrays must specify a max size"); ++ } + dec->array_max = "~0"; /* unspecified size, use max */ + } else { + scan_num(&tok); +@@ -995,7 +998,7 @@ hdle_param_tok(definition * defp, declaration * dec, token * tokp, + Proc_list->component_kind = DEF_PARAM; + Proc_list->code = alloc(250); + Proc_list->scode = alloc(250); +- get_declaration(dec, DEF_PARAM); ++ get_declaration(dec, par_kind); + Proc_list->pl.param_name = dec->name; + get1_param_type(defp, dec, &Proc_list->pl.param_type); + print_param(dec); +diff --git a/src/vlserver/vldbint.xg b/src/vlserver/vldbint.xg +index d97e092..d955a0d 100644 +--- a/src/vlserver/vldbint.xg ++++ b/src/vlserver/vldbint.xg +@@ -200,7 +200,12 @@ const VLOP_DUMP = 0x100; + typedef vldbentry bulkentries<>; + typedef nvldbentry nbulkentries<>; + typedef uvldbentry ubulkentries<>; +-typedef afs_uint32 bulkaddrs<>; ++/* ++ * 500 is an arbitrary implementation limit, larger than what we support storing. ++ * It lets the XDR decoder detect an attack (excessively large input) and reject ++ * it without incurring excessive resource usage. ++ */ ++typedef afs_uint32 bulkaddrs<500>; + + struct VLCallBack { + afs_uint32 CallBackVersion; +diff --git a/src/volser/volint.xg b/src/volser/volint.xg +index 4d20f0a..8c48da3 100644 +--- a/src/volser/volint.xg ++++ b/src/volser/volint.xg +@@ -65,6 +65,7 @@ statindex 16 + %#define VOLDUMPV2_OMITDIRS 1 + + const SIZE = 1024; ++const NMAXNSERVERS = 13; + + struct volser_status { + afs_uint32 volID; /* Volume id--unique over all systems */ +@@ -246,7 +247,7 @@ struct volintSize { + afs_uint64 dump_size; + }; + +-typedef replica manyDests<>; ++typedef replica manyDests; + typedef afs_int32 manyResults<>; + typedef transDebugInfo transDebugEntries<>; + typedef volintInfo volEntries<>; +@@ -255,7 +256,7 @@ typedef volintXInfo volXEntries<>; + + proc CreateVolume( + IN afs_int32 partition, +- string name<>, ++ string name, + IN afs_int32 type, + IN afs_uint32 parent, + INOUT afs_uint32 *volid, +@@ -289,7 +290,7 @@ proc Clone( + IN afs_int32 trans, + IN afs_uint32 purgeVol, + IN afs_int32 newType, +- IN string newName<>, ++ IN string newName, + INOUT afs_uint32 *newVol + ) = VOLCLONE; + +@@ -337,7 +338,7 @@ proc GetStatus( + ) = VOLGETSTATUS; + + proc SignalRestore( +- IN string name<>, ++ IN string name, + int type, + afs_uint32 pid, + afs_uint32 cloneid +@@ -355,7 +356,7 @@ proc ListVolumes( + + proc SetIdsTypes( + IN afs_int32 tId, +- string name<>, ++ string name, + afs_int32 type, + afs_uint32 pId, + afs_uint32 cloneId, +@@ -367,7 +368,7 @@ proc Monitor( + ) = VOLMONITOR; + + proc PartitionInfo( +- IN string name<>, ++ IN string name<4096>, + OUT struct diskPartition *partition + ) = VOLDISKPART; + +@@ -440,7 +441,7 @@ proc DumpV2( + ) split = VOLDUMPV2; + + proc PartitionInfo64( +- IN string name<>, ++ IN string name<4096>, + OUT struct diskPartition64 *partition + ) = VOLDISKPART64; + diff --git a/debian/patches/series b/debian/patches/series index b0ddb1c61..ca165825f 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -22,3 +22,6 @@ 0022-dir-do-not-leak-contents-of-deleted-directory-entrie.patch 0023-Linux-4.9-inode_change_ok-becomes-setattr_prepare.patch 0024-LINUX-Debian-Ubuntu-build-regression-on-kernel-3.16..patch +CVE-2018-16947.patch +CVE-2018-16948.patch +CVE-2018-16949.patch